QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
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
19#include "qgslogger.h"
20#include "qgsmessagelog.h"
22#include "qgsrasterblock.h"
23#include "qgssettings.h"
24
25#define CPL_SUPRESS_CPLUSPLUS //#spellok
26#include "gdal.h"
27#include "gdalwarper.h"
28#include "cpl_string.h"
29
30#include <QNetworkProxy>
31#include <QString>
32#include <QImage>
33#include <QFileInfo>
34#include <mutex>
35
36
38{
39 if ( node->eType != CXT_Element || !EQUAL( node->pszValue, "Option" ) )
40 return {};
41
42 const QString optionName( CPLGetXMLValue( node, "name", nullptr ) );
43 if ( optionName.isEmpty() )
44 return {};
45
46 QgsGdalOption option;
47 option.name = optionName;
48
49 option.description = QString( CPLGetXMLValue( node, "description", nullptr ) );
50 option.scope = QString( CPLGetXMLValue( node, "scope", nullptr ) );
51
53
54 const char *pszType = CPLGetXMLValue( node, "type", nullptr );
55 const char *pszDefault = CPLGetXMLValue( node, "default", nullptr );
56 if ( pszType && EQUAL( pszType, "string-select" ) )
57 {
59 for ( auto psOption = node->psChild; psOption != nullptr; psOption = psOption->psNext )
60 {
61 if ( psOption->eType != CXT_Element ||
62 !EQUAL( psOption->pszValue, "Value" ) ||
63 !psOption->psChild )
64 {
65 continue;
66 }
67 option.options << psOption->psChild->pszValue;
68 }
69 option.defaultValue = pszDefault ? QString( pszDefault ) : option.options.value( 0 );
70 return option;
71 }
72 else if ( pszType && EQUAL( pszType, "boolean" ) )
73 {
75 option.defaultValue = pszDefault ? QString( pszDefault ) : QStringLiteral( "YES" );
76 return option;
77 }
78 else if ( pszType && EQUAL( pszType, "string" ) )
79 {
81 if ( pszDefault )
82 option.defaultValue = QString( pszDefault );
83 return option;
84 }
85 else if ( pszType && ( EQUAL( pszType, "int" ) || EQUAL( pszType, "integer" ) ) )
86 {
88 if ( pszDefault )
89 {
90 bool ok = false;
91 const int defaultInt = QString( pszDefault ).toInt( &ok );
92 if ( ok )
93 option.defaultValue = defaultInt;
94 }
95
96 if ( const char *pszMin = CPLGetXMLValue( node, "min", nullptr ) )
97 {
98 bool ok = false;
99 const int minInt = QString( pszMin ).toInt( &ok );
100 if ( ok )
101 option.minimum = minInt;
102 }
103 if ( const char *pszMax = CPLGetXMLValue( node, "max", nullptr ) )
104 {
105 bool ok = false;
106 const int maxInt = QString( pszMax ).toInt( &ok );
107 if ( ok )
108 option.maximum = maxInt;
109 }
110 return option;
111 }
112 else if ( pszType && ( EQUAL( pszType, "double" ) || EQUAL( pszType, "float" ) ) )
113 {
115 if ( pszDefault )
116 {
117 bool ok = false;
118 const double defaultDouble = QString( pszDefault ).toDouble( &ok );
119 if ( ok )
120 option.defaultValue = defaultDouble;
121 }
122
123 if ( const char *pszMin = CPLGetXMLValue( node, "min", nullptr ) )
124 {
125 bool ok = false;
126 const double minDouble = QString( pszMin ).toDouble( &ok );
127 if ( ok )
128 option.minimum = minDouble;
129 }
130 if ( const char *pszMax = CPLGetXMLValue( node, "max", nullptr ) )
131 {
132 bool ok = false;
133 const double maxDouble = QString( pszMax ).toDouble( &ok );
134 if ( ok )
135 option.maximum = maxDouble;
136 }
137 return option;
138 }
139
140 QgsDebugError( QStringLiteral( "Unhandled GDAL option type: %1" ).arg( pszType ) );
141 return {};
142}
143
144QList<QgsGdalOption> QgsGdalOption::optionsFromXml( const CPLXMLNode *node )
145{
146 QList< QgsGdalOption > options;
147 for ( auto psItem = node->psChild; psItem != nullptr; psItem = psItem->psNext )
148 {
149 const QgsGdalOption option = fromXmlNode( psItem );
150 if ( option.type == QgsGdalOption::Type::Invalid )
151 continue;
152
153 options << option;
154 }
155 return options;
156}
157
158
159//
160// QgsGdalUtils
161//
162
163bool QgsGdalUtils::supportsRasterCreate( GDALDriverH driver )
164{
165 const QString driverShortName = GDALGetDriverShortName( driver );
166 if ( driverShortName == QLatin1String( "SQLite" ) ||
167 driverShortName == QLatin1String( "PDF" ) )
168 {
169 // it supports Create() but only for vector side
170 return false;
171 }
172 return GDALGetMetadataItem( driver, GDAL_DCAP_CREATE, nullptr ) &&
173 GDALGetMetadataItem( driver, GDAL_DCAP_RASTER, nullptr );
174}
175
176gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandMemoryDataset( GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
177{
178 return createMultiBandMemoryDataset( dataType, 1, extent, width, height, crs );
179}
180
181gdal::dataset_unique_ptr QgsGdalUtils::createMultiBandMemoryDataset( GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
182{
183 GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
184 if ( !hDriverMem )
185 {
187 }
188
189 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", width, height, bands, dataType, nullptr ) );
190
191 const double cellSizeX = extent.width() / width;
192 const double cellSizeY = extent.height() / height;
193 double geoTransform[6];
194 geoTransform[0] = extent.xMinimum();
195 geoTransform[1] = cellSizeX;
196 geoTransform[2] = 0;
197 geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
198 geoTransform[4] = 0;
199 geoTransform[5] = -cellSizeY;
200
201 GDALSetProjection( hSrcDS.get(), crs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toLatin1().constData() );
202 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
203 return hSrcDS;
204}
205
206gdal::dataset_unique_ptr QgsGdalUtils::createSingleBandTiffDataset( const QString &filename, GDALDataType dataType, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs )
207{
208 const double cellSizeX = extent.width() / width;
209 const double cellSizeY = extent.height() / height;
210 double geoTransform[6];
211 geoTransform[0] = extent.xMinimum();
212 geoTransform[1] = cellSizeX;
213 geoTransform[2] = 0;
214 geoTransform[3] = extent.yMinimum() + ( cellSizeY * height );
215 geoTransform[4] = 0;
216 geoTransform[5] = -cellSizeY;
217
218 GDALDriverH hDriver = GDALGetDriverByName( "GTiff" );
219 if ( !hDriver )
220 {
222 }
223
224 // Create the output file.
225 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toUtf8().constData(), width, height, 1, dataType, nullptr ) );
226 if ( !hDstDS )
227 {
229 }
230
231 // Write out the projection definition.
232 GDALSetProjection( hDstDS.get(), crs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toLatin1().constData() );
233 GDALSetGeoTransform( hDstDS.get(), geoTransform );
234 return hDstDS;
235}
236
238{
239 if ( image.isNull() )
240 return nullptr;
241
242 const QRgb *rgb = reinterpret_cast<const QRgb *>( image.constBits() );
243 GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
244 if ( !hDriverMem )
245 {
246 return nullptr;
247 }
248 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem, "", image.width(), image.height(), 0, GDT_Byte, nullptr ) );
249
250 char **papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
251 << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
252 << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
253 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 2 ) );
254 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
255 CSLDestroy( papszOptions );
256
257 papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
258 << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
259 << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
260 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 1 ) );
261 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
262 CSLDestroy( papszOptions );
263
264 papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
265 << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
266 << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
267 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) ) );
268 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
269 CSLDestroy( papszOptions );
270
271 papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
272 << QStringLiteral( "PIXELOFFSET=%1" ).arg( sizeof( QRgb ) )
273 << QStringLiteral( "LINEOFFSET=%1" ).arg( image.bytesPerLine() )
274 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( rgb ) + 3 ) );
275 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
276 CSLDestroy( papszOptions );
277
278 return hSrcDS;
279}
280
281gdal::dataset_unique_ptr QgsGdalUtils::blockToSingleBandMemoryDataset( int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType )
282{
283 if ( !block )
284 return nullptr;
285
286 GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
287 if ( !hDriverMem )
288 return nullptr;
289
290 const double cellSizeX = extent.width() / pixelWidth;
291 const double cellSizeY = extent.height() / pixelHeight;
292 double geoTransform[6];
293 geoTransform[0] = extent.xMinimum();
294 geoTransform[1] = cellSizeX;
295 geoTransform[2] = 0;
296 geoTransform[3] = extent.yMinimum() + ( cellSizeY * pixelHeight );
297 geoTransform[4] = 0;
298 geoTransform[5] = -cellSizeY;
299
300 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriverMem, "", pixelWidth, pixelHeight, 0, dataType, nullptr ) );
301
302 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
303 char **papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
304 << QStringLiteral( "PIXELOFFSET=%1" ).arg( dataTypeSize )
305 << QStringLiteral( "LINEOFFSET=%1" ).arg( pixelWidth * dataTypeSize )
306 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( block ) ) );
307 GDALAddBand( hDstDS.get(), dataType, papszOptions );
308 CSLDestroy( papszOptions );
309
310 GDALSetGeoTransform( hDstDS.get(), geoTransform );
311
312 return hDstDS;
313}
314
316{
317 if ( !block )
318 return nullptr;
319
320 gdal::dataset_unique_ptr ret = blockToSingleBandMemoryDataset( block->width(), block->height(), extent, block->bits(), gdalDataTypeFromQgisDataType( block->dataType() ) );
321 if ( ret )
322 {
323 GDALRasterBandH band = GDALGetRasterBand( ret.get(), 1 );
324 if ( band )
325 GDALSetRasterNoDataValue( band, block->noDataValue() );
326 }
327
328 return ret;
329}
330
331
332
334 const QgsPointXY &origin,
335 double gridXSize,
336 double gridYSize,
337 QgsRasterBlock *block )
338{
339 if ( !block )
340 return nullptr;
341
342 GDALDriverH hDriverMem = GDALGetDriverByName( "MEM" );
343 if ( !hDriverMem )
344 return nullptr;
345
346 const double cellSizeX = gridXSize / block->width();
347 const double cellSizeY = gridYSize / block->height();
348 double geoTransform[6];
349 geoTransform[0] = origin.x();
350 geoTransform[1] = cellSizeX * std::cos( rotation );
351 geoTransform[2] = cellSizeY * std::sin( rotation );
352 geoTransform[3] = origin.y();
353 geoTransform[4] = cellSizeX * std::sin( rotation );
354 geoTransform[5] = -cellSizeY * std::cos( rotation );
355
356 GDALDataType dataType = gdalDataTypeFromQgisDataType( block->dataType() );
357 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriverMem, "", block->width(), block->height(), 0, dataType, nullptr ) );
358
359 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
360 char **papszOptions = QgsGdalUtils::papszFromStringList( QStringList()
361 << QStringLiteral( "PIXELOFFSET=%1" ).arg( dataTypeSize )
362 << QStringLiteral( "LINEOFFSET=%1" ).arg( block->width() * dataTypeSize )
363 << QStringLiteral( "DATAPOINTER=%1" ).arg( reinterpret_cast< qulonglong >( block->bits() ) ) );
364 GDALAddBand( hDstDS.get(), dataType, papszOptions );
365 CSLDestroy( papszOptions );
366
367 GDALSetGeoTransform( hDstDS.get(), geoTransform );
368
369 GDALRasterBandH band = GDALGetRasterBand( hDstDS.get(), 1 );
370 if ( band )
371 GDALSetRasterNoDataValue( band, block->noDataValue() );
372
373 return hDstDS;
374}
375
376static bool resampleSingleBandRasterStatic( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, char **papszOptions )
377{
378 gdal::warp_options_unique_ptr psWarpOptions( GDALCreateWarpOptions() );
379 psWarpOptions->hSrcDS = hSrcDS;
380 psWarpOptions->hDstDS = hDstDS;
381
382 psWarpOptions->nBandCount = 1;
383 psWarpOptions->panSrcBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
384 psWarpOptions->panDstBands = reinterpret_cast< int * >( CPLMalloc( sizeof( int ) * 1 ) );
385 psWarpOptions->panSrcBands[0] = 1;
386 psWarpOptions->panDstBands[0] = 1;
387 double noDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( hDstDS, 1 ), nullptr );
388 psWarpOptions->padfDstNoDataReal = reinterpret_cast< double * >( CPLMalloc( sizeof( double ) * 1 ) );
389 psWarpOptions->padfDstNoDataReal[0] = noDataValue;
390 psWarpOptions->padfSrcNoDataReal = reinterpret_cast< double * >( CPLMalloc( sizeof( double ) * 1 ) );
391 psWarpOptions->padfSrcNoDataReal[0] = noDataValue;
392 psWarpOptions->eResampleAlg = resampleAlg;
393
394 // Establish reprojection transformer.
395 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
396
397 if ( ! psWarpOptions->pTransformerArg )
398 {
399 return false;
400 }
401
402 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
403 psWarpOptions->papszWarpOptions = CSLSetNameValue( psWarpOptions-> papszWarpOptions, "INIT_DEST", "NO_DATA" );
404
405 // Initialize and execute the warp operation.
406 bool retVal = false;
407 GDALWarpOperation oOperation;
408 CPLErr initResult = oOperation.Initialize( psWarpOptions.get() );
409 if ( initResult != CE_Failure )
410 retVal = oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None;
411 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
412 return retVal;
413}
414
415bool QgsGdalUtils::resampleSingleBandRaster( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, GDALResampleAlg resampleAlg, const char *pszCoordinateOperation )
416{
417 char **papszOptions = nullptr;
418 if ( pszCoordinateOperation )
419 papszOptions = CSLSetNameValue( papszOptions, "COORDINATE_OPERATION", pszCoordinateOperation );
420
421 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
422 CSLDestroy( papszOptions );
423 return result;
424}
425
427 GDALDatasetH hDstDS,
428 GDALResampleAlg resampleAlg,
429 const QgsCoordinateReferenceSystem &sourceCrs,
430 const QgsCoordinateReferenceSystem &destinationCrs )
431{
432 char **papszOptions = nullptr;
433
434 papszOptions = CSLSetNameValue( papszOptions, "SRC_SRS", sourceCrs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toUtf8().constData() );
435 papszOptions = CSLSetNameValue( papszOptions, "DST_SRS", destinationCrs.toWkt( Qgis::CrsWktVariant::PreferredGdal ).toUtf8().constData() );
436
437 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
438 CSLDestroy( papszOptions );
439 return result;
440}
441
442QImage QgsGdalUtils::resampleImage( const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg )
443{
445 if ( !srcDS )
446 return QImage();
447
448 GDALRasterIOExtraArg extra;
449 INIT_RASTERIO_EXTRA_ARG( extra );
450 extra.eResampleAlg = resampleAlg;
451
452 QImage res( outputSize, image.format() );
453 if ( res.isNull() )
454 return QImage();
455
456 GByte *rgb = reinterpret_cast<GByte *>( res.bits() );
457
458 CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
459 outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
460 if ( err != CE_None )
461 {
462 QgsDebugError( QStringLiteral( "failed to read red band" ) );
463 return QImage();
464 }
465
466 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
467 outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
468 if ( err != CE_None )
469 {
470 QgsDebugError( QStringLiteral( "failed to read green band" ) );
471 return QImage();
472 }
473
474 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
475 outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
476 if ( err != CE_None )
477 {
478 QgsDebugError( QStringLiteral( "failed to read blue band" ) );
479 return QImage();
480 }
481
482 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
483 outputSize.height(), GDT_Byte, sizeof( QRgb ), res.bytesPerLine(), &extra );
484 if ( err != CE_None )
485 {
486 QgsDebugError( QStringLiteral( "failed to read alpha band" ) );
487 return QImage();
488 }
489
490 return res;
491}
492
493QString QgsGdalUtils::helpCreationOptionsFormat( const QString &format )
494{
495 QString message;
496 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
497 if ( myGdalDriver )
498 {
499 // first report details and help page
500 char **GDALmetadata = GDALGetMetadata( myGdalDriver, nullptr );
501 message += QLatin1String( "Format Details:\n" );
502 message += QStringLiteral( " Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
503 message += QStringLiteral( " Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
504 message += QStringLiteral( " / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
505 const QString helpUrl = gdalDocumentationUrlForDriver( myGdalDriver );
506 if ( !helpUrl.isEmpty() )
507 message += QStringLiteral( " Help page: %1\n\n" ).arg( helpUrl );
508
509 // next get creation options
510 // need to serialize xml to get newlines, should we make the basic xml prettier?
511 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
512 GDAL_DMD_CREATIONOPTIONLIST, "" ) );
513 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
514 if ( pszFormattedXML )
515 message += QString( pszFormattedXML );
516 if ( psCOL )
517 CPLDestroyXMLNode( psCOL );
518 if ( pszFormattedXML )
519 CPLFree( pszFormattedXML );
520 }
521 return message;
522}
523
524char **QgsGdalUtils::papszFromStringList( const QStringList &list )
525{
526 char **papszRetList = nullptr;
527 const auto constList = list;
528 for ( const QString &elem : constList )
529 {
530 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
531 }
532 return papszRetList;
533}
534
535QString QgsGdalUtils::validateCreationOptionsFormat( const QStringList &creationOptions, const QString &format )
536{
537 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
538 if ( ! myGdalDriver )
539 return QStringLiteral( "invalid GDAL driver" );
540
541 char **papszOptions = papszFromStringList( creationOptions );
542 // get error string?
543 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
544 CSLDestroy( papszOptions );
545
546 if ( !ok )
547 return QStringLiteral( "Failed GDALValidateCreationOptions() test" );
548 return QString();
549}
550
551static void setRPCTransformerOptions( GDALDatasetH hSrcDS, char ***opts )
552{
553 if ( GDALGetMetadata( hSrcDS, "RPC" ) )
554 {
555 // Some RPC may contain a HEIGHT_DEFAULT entry, that must be used as the
556 // best default for RPC_HEIGHT. See https://github.com/OSGeo/gdal/pull/11989
557 const char *heightStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_DEFAULT", "RPC" );
558 if ( !heightStr )
559 {
560 // Otherwise well-behaved RPC should have height offset which is also
561 // a resaonable default for RPC_HEIGHT.
562 heightStr = GDALGetMetadataItem( hSrcDS, "HEIGHT_OFF", "RPC" );
563 }
564 if ( heightStr )
565 *opts = CSLAddNameValue( *opts, "RPC_HEIGHT", heightStr );
566 }
567}
568
570 GDALDatasetH hSrcDS,
571 const char *pszSrcWKT,
572 const char *pszDstWKT,
573 GDALResampleAlg eResampleAlg,
574 double dfMaxError,
575 const GDALWarpOptions *psOptionsIn )
576{
577 char **opts = nullptr;
578 setRPCTransformerOptions( hSrcDS, &opts );
579 GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
580 CSLDestroy( opts );
581 return hRetDS;
582}
583
584void *QgsGdalUtils::rpcAwareCreateTransformer( GDALDatasetH hSrcDS, GDALDatasetH hDstDS, char **papszOptions )
585{
586 char **opts = CSLDuplicate( papszOptions );
587 setRPCTransformerOptions( hSrcDS, &opts );
588 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
589 CSLDestroy( opts );
590 return transformer;
591}
592
594{
595 switch ( dataType )
596 {
598 return GDALDataType::GDT_Unknown;
599 break;
601 return GDALDataType::GDT_Byte;
602 break;
604#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
605 return GDALDataType::GDT_Int8;
606#else
607 return GDALDataType::GDT_Unknown;
608#endif
609 break;
611 return GDALDataType::GDT_UInt16;
612 break;
614 return GDALDataType::GDT_Int16;
615 break;
617 return GDALDataType::GDT_UInt32;
618 break;
620 return GDALDataType::GDT_Int32;
621 break;
623 return GDALDataType::GDT_Float32;
624 break;
626 return GDALDataType::GDT_Float64;
627 break;
629 return GDALDataType::GDT_CInt16;
630 break;
632 return GDALDataType::GDT_CInt32;
633 break;
635 return GDALDataType::GDT_CFloat32;
636 break;
638 return GDALDataType::GDT_CFloat64;
639 break;
642 return GDALDataType::GDT_Unknown;
643 break;
644 };
645
646 return GDALDataType::GDT_Unknown;
647}
648
650{
651 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
652 switch ( method )
653 {
655 case Qgis::RasterResamplingMethod::Gauss: // Gauss not available in GDALResampleAlg
656 eResampleAlg = GRA_NearestNeighbour;
657 break;
658
660 eResampleAlg = GRA_Bilinear;
661 break;
662
664 eResampleAlg = GRA_Cubic;
665 break;
666
668 eResampleAlg = GRA_CubicSpline;
669 break;
670
672 eResampleAlg = GRA_Lanczos;
673 break;
674
676 eResampleAlg = GRA_Average;
677 break;
678
680 eResampleAlg = GRA_Mode;
681 break;
682 }
683
684 return eResampleAlg;
685}
686
687#ifndef QT_NO_NETWORKPROXY
689{
690 // Check proxy configuration, they are application level but
691 // instead of adding an API and complex signal/slot connections
692 // given the limited cost of checking them on every provider instantiation
693 // we can do it here so that new settings are applied whenever a new layer
694 // is created.
695 const QgsSettings settings;
696 // Check that proxy is enabled
697 if ( settings.value( QStringLiteral( "proxy/proxyEnabled" ), false ).toBool() )
698 {
699 // Get the first configured proxy
700 QList<QNetworkProxy> proxies( QgsNetworkAccessManager::instance()->proxyFactory()->queryProxy( ) );
701 if ( ! proxies.isEmpty() )
702 {
703 const QNetworkProxy proxy( proxies.first() );
704 // TODO/FIXME: check excludes (the GDAL config options are global, we need a per-connection config option)
705 //QStringList excludes;
706 //excludes = settings.value( QStringLiteral( "proxy/proxyExcludedUrls" ), "" ).toStringList();
707
708 const QString proxyHost( proxy.hostName() );
709 const quint16 proxyPort( proxy.port() );
710
711 const QString proxyUser( proxy.user() );
712 const QString proxyPassword( proxy.password() );
713
714 if ( ! proxyHost.isEmpty() )
715 {
716 QString connection( proxyHost );
717 if ( proxyPort )
718 {
719 connection += ':' + QString::number( proxyPort );
720 }
721 CPLSetConfigOption( "GDAL_HTTP_PROXY", connection.toUtf8() );
722 if ( ! proxyUser.isEmpty( ) )
723 {
724 QString credentials( proxyUser );
725 if ( ! proxyPassword.isEmpty( ) )
726 {
727 credentials += ':' + proxyPassword;
728 }
729 CPLSetConfigOption( "GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
730 }
731 }
732 }
733 }
734}
735
736bool QgsGdalUtils::pathIsCheapToOpen( const QString &path, int smallFileSizeLimit )
737{
738 const QFileInfo info( path );
739 const long long size = info.size();
740
741 // if size could not be determined, safest to flag path as expensive
742 if ( size == 0 )
743 return false;
744
745 const QString suffix = info.suffix().toLower();
746 static const QStringList sFileSizeDependentExtensions
747 {
748 QStringLiteral( "xlsx" ),
749 QStringLiteral( "ods" ),
750 QStringLiteral( "csv" )
751 };
752 if ( sFileSizeDependentExtensions.contains( suffix ) )
753 {
754 // path corresponds to a file type which is only cheap to open for small files
755 return size < smallFileSizeLimit;
756 }
757
758 // treat all other formats as expensive.
759 // TODO -- flag formats which only require a quick header parse as cheap
760 return false;
761}
762
764{
765#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
766 // get supported extensions
767 static std::once_flag initialized;
768 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
769 std::call_once( initialized, []
770 {
771 // iterate through all of the supported drivers, adding the corresponding file extensions for
772 // types which advertise multilayer support
773 GDALDriverH driver = nullptr;
774
775 QSet< QString > extensions;
776
777 for ( int i = 0; i < GDALGetDriverCount(); ++i )
778 {
779 driver = GDALGetDriver( i );
780 if ( !driver )
781 {
782 QgsLogger::warning( "unable to get driver " + QString::number( i ) );
783 continue;
784 }
785
786 bool isMultiLayer = false;
787 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER, nullptr ) ) == QLatin1String( "YES" ) )
788 {
789 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS, nullptr ) )
790 {
791 isMultiLayer = true;
792 }
793 }
794 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR, nullptr ) ) == QLatin1String( "YES" ) )
795 {
796 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, nullptr ) )
797 {
798 isMultiLayer = true;
799 }
800 }
801
802 if ( !isMultiLayer )
803 continue;
804
805 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS, "" );
806 if ( driverExtensions.isEmpty() )
807 continue;
808
809 const QStringList splitExtensions = driverExtensions.split( ' ', Qt::SkipEmptyParts );
810
811 for ( const QString &ext : splitExtensions )
812 {
813 // maintain older behavior -- don't always expose tiff files as containers
814 if ( ext == QLatin1String( "tif" ) || ext == QLatin1String( "tiff" ) )
815 continue;
816
817 extensions.insert( ext );
818 }
819 }
820
821 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
822 } );
823 return SUPPORTED_DB_LAYERS_EXTENSIONS;
824
825#else
826 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
827 {
828 QStringLiteral( "gpkg" ),
829 QStringLiteral( "sqlite" ),
830 QStringLiteral( "db" ),
831 QStringLiteral( "gdb" ),
832 QStringLiteral( "kml" ),
833 QStringLiteral( "kmz" ),
834 QStringLiteral( "osm" ),
835 QStringLiteral( "mdb" ),
836 QStringLiteral( "accdb" ),
837 QStringLiteral( "xls" ),
838 QStringLiteral( "xlsx" ),
839 QStringLiteral( "ods" ),
840 QStringLiteral( "gpx" ),
841 QStringLiteral( "pdf" ),
842 QStringLiteral( "pbf" ),
843 QStringLiteral( "vrt" ),
844 QStringLiteral( "nc" ),
845 QStringLiteral( "dxf" ),
846 QStringLiteral( "shp.zip" ),
847 QStringLiteral( "gdb.zip" ) };
848 return SUPPORTED_DB_LAYERS_EXTENSIONS;
849#endif
850}
851
852QString QgsGdalUtils::vsiPrefixForPath( const QString &path )
853{
854 const QStringList vsiPrefixes = QgsGdalUtils::vsiArchivePrefixes();
855
856 const thread_local QRegularExpression vsiRx( QStringLiteral( "^(/vsi.+?/)" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
857 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
858 if ( vsiMatch.hasMatch() )
859 return vsiMatch.captured( 1 );
860
861 if ( path.endsWith( QLatin1String( ".shp.zip" ), Qt::CaseInsensitive ) ||
862 path.endsWith( QLatin1String( ".gdb.zip" ), Qt::CaseInsensitive ) )
863 {
864 // GDAL 3.1 Shapefile/OpenFileGDB drivers directly handle .shp.zip and .gdb.zip files
865 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr ) )
866 return QString();
867 return QStringLiteral( "/vsizip/" );
868 }
869 else if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) )
870 {
871 // GTFS driver directly handles .zip files
872 const char *const apszAllowedDrivers[] = { "GTFS", nullptr };
873 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers, nullptr ) )
874 return QString();
875 return QStringLiteral( "/vsizip/" );
876 }
877 else if ( path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) ||
878 path.endsWith( QLatin1String( ".tar.gz" ), Qt::CaseInsensitive ) ||
879 path.endsWith( QLatin1String( ".tgz" ), Qt::CaseInsensitive ) )
880 return QStringLiteral( "/vsitar/" );
881 else if ( path.endsWith( QLatin1String( ".gz" ), Qt::CaseInsensitive ) )
882 return QStringLiteral( "/vsigzip/" );
883#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
884 else if ( vsiPrefixes.contains( QStringLiteral( "/vsi7z/" ) ) &&
885 ( path.endsWith( QLatin1String( ".7z" ), Qt::CaseInsensitive ) ||
886 path.endsWith( QLatin1String( ".lpk" ), Qt::CaseInsensitive ) ||
887 path.endsWith( QLatin1String( ".lpkx" ), Qt::CaseInsensitive ) ||
888 path.endsWith( QLatin1String( ".mpk" ), Qt::CaseInsensitive ) ||
889 path.endsWith( QLatin1String( ".mpkx" ), Qt::CaseInsensitive ) ) )
890 return QStringLiteral( "/vsi7z/" );
891 else if ( vsiPrefixes.contains( QStringLiteral( "/vsirar/" ) ) &&
892 path.endsWith( QLatin1String( ".rar" ), Qt::CaseInsensitive ) )
893 return QStringLiteral( "/vsirar/" );
894#endif
895
896 return QString();
897}
898
900{
901 QStringList res { QStringLiteral( "/vsizip/" ),
902 QStringLiteral( "/vsitar/" ),
903 QStringLiteral( "/vsigzip/" ),
904 };
905#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
906 res.append( QStringLiteral( "/vsi7z/" ) );
907 res.append( QStringLiteral( "/vsirar/" ) );
908#endif
909 return res;
910}
911
912QList<QgsGdalUtils::VsiNetworkFileSystemDetails> QgsGdalUtils::vsiNetworkFileSystems()
913{
914 // get supported extensions
915 static std::once_flag initialized;
916 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
917 std::call_once( initialized, []
918 {
919 if ( char **papszPrefixes = VSIGetFileSystemsPrefixes() )
920 {
921 for ( int i = 0; papszPrefixes[i]; i++ )
922 {
924 details.identifier = QString( papszPrefixes[i] );
925 if ( details.identifier.startsWith( '/' ) )
926 details.identifier = details.identifier.mid( 1 );
927 if ( details.identifier.endsWith( '/' ) )
928 details.identifier.chop( 1 );
929
930 if ( details.identifier == QLatin1String( "vsicurl" ) )
931 details.name = QObject::tr( "HTTP/HTTPS/FTP" );
932 else if ( details.identifier == QLatin1String( "vsis3" ) )
933 details.name = QObject::tr( "AWS S3" );
934 else if ( details.identifier == QLatin1String( "vsigs" ) )
935 details.name = QObject::tr( "Google Cloud Storage" );
936 else if ( details.identifier == QLatin1String( "vsiaz" ) )
937 details.name = QObject::tr( "Microsoft Azure Blob" );
938 else if ( details.identifier == QLatin1String( "vsiadls" ) )
939 details.name = QObject::tr( "Microsoft Azure Data Lake Storage" );
940 else if ( details.identifier == QLatin1String( "vsioss" ) )
941 details.name = QObject::tr( "Alibaba Cloud OSS" );
942 else if ( details.identifier == QLatin1String( "vsiswift" ) )
943 details.name = QObject::tr( "OpenStack Swift Object Storage" );
944 else if ( details.identifier == QLatin1String( "vsihdfs" ) )
945 details.name = QObject::tr( "Hadoop File System" );
946 else
947 continue;
948 VSI_FILE_SYSTEM_DETAILS.append( details );
949 }
950
951 CSLDestroy( papszPrefixes );
952 }
953 } );
954
955 return VSI_FILE_SYSTEM_DETAILS;
956}
957
958bool QgsGdalUtils::isVsiArchivePrefix( const QString &prefix )
959{
960 const QStringList prefixes = vsiArchivePrefixes();
961 for ( const QString &archivePrefix : prefixes )
962 {
963 // catch chained prefixes, eg "/vsizip/vsicurl"
964 if ( prefix.contains( archivePrefix ) )
965 return true;
966 }
967 return false;
968}
969
971{
972 QStringList res { QStringLiteral( ".zip" ),
973 QStringLiteral( ".tar" ),
974 QStringLiteral( ".tar.gz" ),
975 QStringLiteral( ".tgz" ),
976 QStringLiteral( ".gz" ),
977 };
978#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
979 res.append( { QStringLiteral( ".7z" ),
980 QStringLiteral( ".lpk" ),
981 QStringLiteral( ".lpkx" ),
982 QStringLiteral( ".mpk" ),
983 QStringLiteral( ".mpkx" ),
984 QStringLiteral( ".rar" )
985 } );
986#endif
987 return res;
988}
989
990bool QgsGdalUtils::isVsiArchiveFileExtension( const QString &extension )
991{
992 const QString extWithDot = extension.startsWith( '.' ) ? extension : ( '.' + extension );
993 return vsiArchiveFileExtensions().contains( extWithDot.toLower() );
994}
995
997{
998 if ( prefix.isEmpty() )
1000
1001 QString vsiPrefix = prefix;
1002 if ( vsiPrefix.startsWith( '/' ) )
1003 vsiPrefix = vsiPrefix.mid( 1 );
1004 if ( vsiPrefix.endsWith( '/' ) )
1005 vsiPrefix.chop( 1 );
1006
1007 if ( !vsiPrefix.startsWith( QLatin1String( "vsi" ) ) )
1009
1010 if ( vsiPrefix == QLatin1String( "vsizip" ) ||
1011 vsiPrefix == QLatin1String( "vsigzip" ) ||
1012 vsiPrefix == QLatin1String( "vsitar" ) ||
1013 vsiPrefix == QLatin1String( "vsi7z" ) ||
1014 vsiPrefix == QLatin1String( "vsirar" ) )
1016
1017 else if ( vsiPrefix == QLatin1String( "vsicurl" ) ||
1018 vsiPrefix == QLatin1String( "vsicurl_streaming" ) )
1020
1021 else if ( vsiPrefix == QLatin1String( "vsis3" ) ||
1022 vsiPrefix == QLatin1String( "vsicurl_streaming" ) ||
1023 vsiPrefix == QLatin1String( "vsigs" ) ||
1024 vsiPrefix == QLatin1String( "vsigs_streaming" ) ||
1025 vsiPrefix == QLatin1String( "vsiaz" ) ||
1026 vsiPrefix == QLatin1String( "vsiaz_streaming" ) ||
1027 vsiPrefix == QLatin1String( "vsiadls" ) ||
1028 vsiPrefix == QLatin1String( "vsioss" ) ||
1029 vsiPrefix == QLatin1String( "vsioss_streaming" ) ||
1030 vsiPrefix == QLatin1String( "vsiswift" ) ||
1031 vsiPrefix == QLatin1String( "vsiswift_streaming" ) ||
1032 vsiPrefix == QLatin1String( "vsihdfs" ) ||
1033 vsiPrefix == QLatin1String( "vsiwebhdfs" ) )
1035
1036 else if ( vsiPrefix == QLatin1String( "vsimem" ) )
1038
1040}
1041
1042bool QgsGdalUtils::vrtMatchesLayerType( const QString &vrtPath, Qgis::LayerType type )
1043{
1044 CPLPushErrorHandler( CPLQuietErrorHandler );
1045 CPLErrorReset();
1046 GDALDriverH hDriver = nullptr;
1047
1048 switch ( type )
1049 {
1051 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR, nullptr, nullptr );
1052 break;
1053
1055 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER, nullptr, nullptr );
1056 break;
1057
1065 break;
1066 }
1067
1068 CPLPopErrorHandler();
1069 return static_cast< bool >( hDriver );
1070}
1071
1073{
1074 if ( hDriver )
1075 {
1076 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC, nullptr ); // e.g. "drivers/vector/ili.html"
1077 if ( !gdalDriverHelpTopic.isEmpty() )
1078 return QStringLiteral( "https://gdal.org/%1" ).arg( gdalDriverHelpTopic );
1079 }
1080 return QString();
1081}
1082
1083bool QgsGdalUtils::applyVsiCredentialOptions( const QString &prefix, const QString &path, const QVariantMap &options )
1084{
1085 QString vsiPrefix = prefix;
1086 if ( !vsiPrefix.startsWith( '/' ) )
1087 vsiPrefix.prepend( '/' );
1088 if ( !vsiPrefix.endsWith( '/' ) )
1089 vsiPrefix.append( '/' );
1090
1091 QString vsiPath = path;
1092 if ( vsiPath.endsWith( '/' ) )
1093 vsiPath.chop( 1 );
1094
1095 const QString bucket = vsiPrefix + vsiPath;
1096
1097 for ( auto it = options.constBegin(); it != options.constEnd(); ++it )
1098 {
1099#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0)
1100 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1101#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 5, 0)
1102 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1103#else
1104 ( void )bucket;
1105 QgsMessageLog::logMessage( QObject::tr( "Cannot use VSI credential options on GDAL versions earlier than 3.5" ), QStringLiteral( "GDAL" ), Qgis::MessageLevel::Critical );
1106 return false;
1107#endif
1108 }
1109 return true;
1110}
1111#endif
VsiHandlerType
GDAL VSI handler types.
Definition qgis.h:5744
@ Memory
In-memory types (e.g. vsimem).
Definition qgis.h:5749
@ Invalid
Invalid type, i.e. not a valid VSI handler.
Definition qgis.h:5745
@ Other
All other types.
Definition qgis.h:5750
@ Cloud
Specific cloud provider types (e.g. vsis3).
Definition qgis.h:5748
@ Archive
File archive type (e.g. vsizip).
Definition qgis.h:5746
@ Network
Generic network types (e.g. vsicurl).
Definition qgis.h:5747
RasterResamplingMethod
Resampling method for raster provider-level resampling.
Definition qgis.h:1484
@ Lanczos
Lanczos windowed sinc interpolation (6x6 kernel).
Definition qgis.h:1489
@ Nearest
Nearest-neighbour resampling.
Definition qgis.h:1485
@ Mode
Mode (selects the value which appears most often of all the sampled points).
Definition qgis.h:1491
@ Bilinear
Bilinear (2x2 kernel) resampling.
Definition qgis.h:1486
@ Average
Average resampling.
Definition qgis.h:1490
@ CubicSpline
Cubic B-Spline Approximation (4x4 kernel).
Definition qgis.h:1488
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
Definition qgis.h:1487
@ Gauss
Gauss blurring.
Definition qgis.h:1492
@ Critical
Critical/error message.
Definition qgis.h:159
DataType
Raster data types.
Definition qgis.h:372
@ CInt32
Complex Int32.
Definition qgis.h:383
@ Float32
Thirty two bit floating point (float).
Definition qgis.h:380
@ CFloat64
Complex Float64.
Definition qgis.h:385
@ Int16
Sixteen bit signed integer (qint16).
Definition qgis.h:377
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
Definition qgis.h:387
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
Definition qgis.h:375
@ UInt16
Sixteen bit unsigned integer (quint16).
Definition qgis.h:376
@ Byte
Eight bit unsigned integer (quint8).
Definition qgis.h:374
@ UnknownDataType
Unknown or unspecified type.
Definition qgis.h:373
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
Definition qgis.h:386
@ Int32
Thirty two bit signed integer (qint32).
Definition qgis.h:379
@ Float64
Sixty four bit floating point (double).
Definition qgis.h:381
@ CFloat32
Complex Float32.
Definition qgis.h:384
@ CInt16
Complex Int16.
Definition qgis.h:382
@ UInt32
Thirty two bit unsigned integer (quint32).
Definition qgis.h:378
LayerType
Types of layers that can be added to a map.
Definition qgis.h:190
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:198
@ Plugin
Plugin based layer.
Definition qgis.h:193
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:199
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:196
@ Vector
Vector layer.
Definition qgis.h:191
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:195
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:194
@ Raster
Raster layer.
Definition qgis.h:192
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:197
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
Definition qgis.h:2441
Represents a coordinate reference system (CRS).
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Encapsulates the definition of a GDAL configuration option.
QVariant defaultValue
Default value.
QVariant maximum
Maximum acceptable value.
QString name
Option name.
QStringList options
Available choices, for Select options.
QVariant minimum
Minimum acceptable value.
@ Int
Integer option.
@ Boolean
Boolean option.
@ Invalid
Invalid option.
@ Text
Text option.
@ Double
Double option.
@ Select
Selection option.
QString scope
Option scope.
static QList< QgsGdalOption > optionsFromXml(const CPLXMLNode *node)
Returns a list of all GDAL options from an XML node.
static QgsGdalOption fromXmlNode(const CPLXMLNode *node)
Creates a QgsGdalOption from an XML node.
QString description
Option description.
Type type
Option type.
static Qgis::VsiHandlerType vsiHandlerType(const QString &prefix)
Returns the VSI handler type for a given VSI prefix.
static bool applyVsiCredentialOptions(const QString &prefix, const QString &path, const QVariantMap &options)
Attempts to apply VSI credential options.
static bool pathIsCheapToOpen(const QString &path, int smallFileSizeLimit=50000)
Returns true if the dataset at the specified path is considered "cheap" to open.
static QString vsiPrefixForPath(const QString &path)
Returns a the vsi prefix which corresponds to a file path, or an empty string if the path is not asso...
static QString helpCreationOptionsFormat(const QString &format)
Gets creation options metadata for a given format.
static bool vrtMatchesLayerType(const QString &vrtPath, Qgis::LayerType type)
Returns true if the VRT file at the specified path is a VRT matching the given layer type.
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 bool isVsiArchiveFileExtension(const QString &extension)
Returns true if a file extension is a supported archive style container (e.g.
static GDALResampleAlg gdalResamplingAlgorithm(Qgis::RasterResamplingMethod method)
Returns the GDAL resampling method corresponding to the QGIS resampling method.
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 GDALDataType gdalDataTypeFromQgisDataType(Qgis::DataType dataType)
Returns the GDAL data type corresponding to the QGIS data type dataType.
static bool isVsiArchivePrefix(const QString &prefix)
Returns true if prefix is a supported archive style container prefix (e.g.
static QString gdalDocumentationUrlForDriver(GDALDriverH hDriver)
Returns the URL for the GDAL documentation for the specified driver.
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 gdal::dataset_unique_ptr blockToSingleBandMemoryDataset(int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType)
Converts a data block to a single band GDAL memory dataset.
static QList< VsiNetworkFileSystemDetails > vsiNetworkFileSystems()
Returns a list of available GDAL VSI network file systems.
static QString validateCreationOptionsFormat(const QStringList &creationOptions, 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 QStringList vsiArchiveFileExtensions()
Returns a list of file extensions which correspond to archive style containers supported by GDAL (e....
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 QStringList multiLayerFileExtensions()
Returns a list of file extensions which potentially contain multiple layers representing GDAL raster ...
static QStringList vsiArchivePrefixes()
Returns a list of vsi prefixes which correspond to archive style containers (eg vsizip).
static void warning(const QString &msg)
Goes to qWarning.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Represents a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
Raster data container.
int height() const
Returns the height (number of rows) of the raster block.
char * bits(int row, int column)
Returns a pointer to block data.
double noDataValue() const
Returns no data value.
Qgis::DataType dataType() const
Returns data type.
int width() const
Returns the width (number of columns) of the raster block.
A rectangle specified with double values.
double xMinimum
double yMinimum
Stores settings for use within QGIS.
Definition qgssettings.h:65
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
void * GDALDatasetH
#define QgsDebugError(str)
Definition qgslogger.h:57
Encapsulates details for a GDAL VSI network file system.
QString name
Translated, user-friendly name.
QString identifier
VSI handler identifier, eg "vsis3".