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