27using namespace Qt::StringLiterals;
29#define CPL_SUPRESS_CPLUSPLUS
31#include "gdalwarper.h"
32#include "cpl_string.h"
34#include <QNetworkProxy>
43 if ( node->eType != CXT_Element || !EQUAL( node->pszValue,
"Option" ) )
46 const QString optionName( CPLGetXMLValue( node,
"name",
nullptr ) );
47 if ( optionName.isEmpty() )
51 option.
name = optionName;
53 option.
description = QString( CPLGetXMLValue( node,
"description",
nullptr ) );
54 option.
scope = QString( CPLGetXMLValue( node,
"scope",
nullptr ) );
58 const char *pszType = CPLGetXMLValue( node,
"type",
nullptr );
59 const char *pszDefault = CPLGetXMLValue( node,
"default",
nullptr );
60 if ( pszType && EQUAL( pszType,
"string-select" ) )
63 for (
auto psOption = node->psChild; psOption !=
nullptr; psOption = psOption->psNext )
65 if ( psOption->eType != CXT_Element ||
66 !EQUAL( psOption->pszValue,
"Value" ) ||
71 option.
options << psOption->psChild->pszValue;
76 else if ( pszType && EQUAL( pszType,
"boolean" ) )
79 option.
defaultValue = pszDefault ? QString( pszDefault ) : u
"YES"_s;
82 else if ( pszType && EQUAL( pszType,
"string" ) )
89 else if ( pszType && ( EQUAL( pszType,
"int" ) || EQUAL( pszType,
"integer" ) ) )
95 const int defaultInt = QString( pszDefault ).toInt( &ok );
100 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
103 const int minInt = QString( pszMin ).toInt( &ok );
107 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
110 const int maxInt = QString( pszMax ).toInt( &ok );
116 else if ( pszType && ( EQUAL( pszType,
"double" ) || EQUAL( pszType,
"float" ) ) )
122 const double defaultDouble = QString( pszDefault ).toDouble( &ok );
127 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
130 const double minDouble = QString( pszMin ).toDouble( &ok );
134 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
137 const double maxDouble = QString( pszMax ).toDouble( &ok );
144 QgsDebugError( u
"Unhandled GDAL option type: %1"_s.arg( pszType ) );
150 QList< QgsGdalOption >
options;
151 for (
auto psItem = node->psChild; psItem !=
nullptr; psItem = psItem->psNext )
169 const QString driverShortName = GDALGetDriverShortName( driver );
170 if ( driverShortName ==
"SQLite"_L1 ||
171 driverShortName ==
"PDF"_L1 )
176 return GDALGetMetadataItem( driver, GDAL_DCAP_CREATE,
nullptr ) &&
177 GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr );
187 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
195 const double cellSizeX = extent.
width() / width;
196 const double cellSizeY = extent.
height() / height;
197 double geoTransform[6];
198 geoTransform[0] = extent.
xMinimum();
199 geoTransform[1] = cellSizeX;
201 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
203 geoTransform[5] = -cellSizeY;
206 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
212 const double cellSizeX = extent.
width() / width;
213 const double cellSizeY = extent.
height() / height;
214 double geoTransform[6];
215 geoTransform[0] = extent.
xMinimum();
216 geoTransform[1] = cellSizeX;
218 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
220 geoTransform[5] = -cellSizeY;
222 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
229 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toUtf8().constData(), width, height, 1, dataType,
nullptr ) );
237 GDALSetGeoTransform( hDstDS.get(), geoTransform );
243 if ( image.isNull() )
246 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( image.constBits() );
247 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
252 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem,
"", image.width(), image.height(), 0, GDT_Byte,
nullptr ) );
255 << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) )
256 << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() )
257 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 2 ) );
258 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
259 CSLDestroy( papszOptions );
262 << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) )
263 << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() )
264 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 1 ) );
265 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
266 CSLDestroy( papszOptions );
269 << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) )
270 << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() )
271 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) ) );
272 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
273 CSLDestroy( papszOptions );
276 << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) )
277 << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() )
278 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 3 ) );
279 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
280 CSLDestroy( papszOptions );
290 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
294 const double cellSizeX = extent.
width() / pixelWidth;
295 const double cellSizeY = extent.
height() / pixelHeight;
296 double geoTransform[6];
297 geoTransform[0] = extent.
xMinimum();
298 geoTransform[1] = cellSizeX;
300 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * pixelHeight );
302 geoTransform[5] = -cellSizeY;
306 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
308 << u
"PIXELOFFSET=%1"_s.arg( dataTypeSize )
309 << u
"LINEOFFSET=%1"_s.arg( pixelWidth * dataTypeSize )
310 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( block ) ) );
311 GDALAddBand( hDstDS.get(), dataType, papszOptions );
312 CSLDestroy( papszOptions );
314 GDALSetGeoTransform( hDstDS.get(), geoTransform );
327 GDALRasterBandH band = GDALGetRasterBand( ret.get(), 1 );
329 GDALSetRasterNoDataValue( band, block->
noDataValue() );
346 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
350 const double cellSizeX = gridXSize / block->
width();
351 const double cellSizeY = gridYSize / block->
height();
352 double geoTransform[6];
353 geoTransform[0] = origin.
x();
354 geoTransform[1] = cellSizeX * std::cos( rotation );
355 geoTransform[2] = cellSizeY * std::sin( rotation );
356 geoTransform[3] = origin.
y();
357 geoTransform[4] = cellSizeX * std::sin( rotation );
358 geoTransform[5] = -cellSizeY * std::cos( rotation );
363 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
365 << u
"PIXELOFFSET=%1"_s.arg( dataTypeSize )
366 << u
"LINEOFFSET=%1"_s.arg( block->
width() * dataTypeSize )
367 << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( block->
bits() ) ) );
368 GDALAddBand( hDstDS.get(), dataType, papszOptions );
369 CSLDestroy( papszOptions );
371 GDALSetGeoTransform( hDstDS.get(), geoTransform );
373 GDALRasterBandH band = GDALGetRasterBand( hDstDS.get(), 1 );
375 GDALSetRasterNoDataValue( band, block->
noDataValue() );
380static bool resampleSingleBandRasterStatic(
GDALDatasetH hSrcDS,
GDALDatasetH hDstDS, GDALResampleAlg resampleAlg,
char **papszOptions )
383 psWarpOptions->hSrcDS = hSrcDS;
384 psWarpOptions->hDstDS = hDstDS;
386 psWarpOptions->nBandCount = 1;
387 psWarpOptions->panSrcBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
388 psWarpOptions->panDstBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
389 psWarpOptions->panSrcBands[0] = 1;
390 psWarpOptions->panDstBands[0] = 1;
391 double noDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( hDstDS, 1 ),
nullptr );
392 psWarpOptions->padfDstNoDataReal =
reinterpret_cast< double *
>( CPLMalloc(
sizeof(
double ) * 1 ) );
393 psWarpOptions->padfDstNoDataReal[0] = noDataValue;
394 psWarpOptions->padfSrcNoDataReal =
reinterpret_cast< double *
>( CPLMalloc(
sizeof(
double ) * 1 ) );
395 psWarpOptions->padfSrcNoDataReal[0] = noDataValue;
396 psWarpOptions->eResampleAlg = resampleAlg;
399 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
401 if ( ! psWarpOptions->pTransformerArg )
406 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
407 psWarpOptions->papszWarpOptions = CSLSetNameValue( psWarpOptions-> papszWarpOptions,
"INIT_DEST",
"NO_DATA" );
411 GDALWarpOperation oOperation;
412 CPLErr initResult = oOperation.Initialize( psWarpOptions.get() );
413 if ( initResult != CE_Failure )
414 retVal = oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None;
415 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
421 char **papszOptions =
nullptr;
422 if ( pszCoordinateOperation )
423 papszOptions = CSLSetNameValue( papszOptions,
"COORDINATE_OPERATION", pszCoordinateOperation );
425 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
426 CSLDestroy( papszOptions );
432 GDALResampleAlg resampleAlg,
436 char **papszOptions =
nullptr;
441 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
442 CSLDestroy( papszOptions );
452 GDALRasterIOExtraArg extra;
453 INIT_RASTERIO_EXTRA_ARG( extra );
454 extra.eResampleAlg = resampleAlg;
456 QImage res( outputSize, image.format() );
460 GByte *rgb =
reinterpret_cast<GByte *
>( res.bits() );
462 CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
463 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
464 if ( err != CE_None )
470 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
471 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
472 if ( err != CE_None )
478 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
479 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
480 if ( err != CE_None )
486 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
487 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
488 if ( err != CE_None )
500 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
504 CSLConstList GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
505 message +=
"Format Details:\n"_L1;
506 message += u
" Extension: %1\n"_s.arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
507 message += u
" Short Name: %1"_s.arg( GDALGetDriverShortName( myGdalDriver ) );
508 message += u
" / Long Name: %1\n"_s.arg( GDALGetDriverLongName( myGdalDriver ) );
510 if ( !helpUrl.isEmpty() )
511 message += u
" Help page: %1\n\n"_s.arg( helpUrl );
515 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
516 GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
517 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
518 if ( pszFormattedXML )
519 message += QString( pszFormattedXML );
521 CPLDestroyXMLNode( psCOL );
522 if ( pszFormattedXML )
523 CPLFree( pszFormattedXML );
530 char **papszRetList =
nullptr;
531 const auto constList = list;
532 for (
const QString &elem : constList )
534 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
541 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
542 if ( ! myGdalDriver )
543 return u
"invalid GDAL driver"_s;
547 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
548 CSLDestroy( papszOptions );
551 return u
"Failed GDALValidateCreationOptions() test"_s;
555static void setRPCTransformerOptions(
GDALDatasetH hSrcDS,
char ***opts )
557 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
561 const char *heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_DEFAULT",
"RPC" );
566 heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
569 *opts = CSLAddNameValue( *opts,
"RPC_HEIGHT", heightStr );
575 const char *pszSrcWKT,
576 const char *pszDstWKT,
577 GDALResampleAlg eResampleAlg,
579 const GDALWarpOptions *psOptionsIn )
581 char **opts =
nullptr;
582 setRPCTransformerOptions( hSrcDS, &opts );
583 GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
590 char **opts = CSLDuplicate( papszOptions );
591 setRPCTransformerOptions( hSrcDS, &opts );
592 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
602 return GDALDataType::GDT_Unknown;
605 return GDALDataType::GDT_Byte;
608#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
609 return GDALDataType::GDT_Int8;
611 return GDALDataType::GDT_Unknown;
615 return GDALDataType::GDT_UInt16;
618 return GDALDataType::GDT_Int16;
621 return GDALDataType::GDT_UInt32;
624 return GDALDataType::GDT_Int32;
627 return GDALDataType::GDT_Float32;
630 return GDALDataType::GDT_Float64;
633 return GDALDataType::GDT_CInt16;
636 return GDALDataType::GDT_CInt32;
639 return GDALDataType::GDT_CFloat32;
642 return GDALDataType::GDT_CFloat64;
646 return GDALDataType::GDT_Unknown;
650 return GDALDataType::GDT_Unknown;
655 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
660 eResampleAlg = GRA_NearestNeighbour;
664 eResampleAlg = GRA_Bilinear;
668 eResampleAlg = GRA_Cubic;
672 eResampleAlg = GRA_CubicSpline;
676 eResampleAlg = GRA_Lanczos;
680 eResampleAlg = GRA_Average;
684 eResampleAlg = GRA_Mode;
691#ifndef QT_NO_NETWORKPROXY
701 if ( settings.
value( u
"proxy/proxyEnabled"_s,
false ).toBool() )
705 if ( ! proxies.isEmpty() )
707 const QNetworkProxy proxy( proxies.first() );
712 const QString proxyHost( proxy.hostName() );
713 const quint16 proxyPort( proxy.port() );
715 const QString proxyUser( proxy.user() );
716 const QString proxyPassword( proxy.password() );
718 if ( ! proxyHost.isEmpty() )
720 QString connection( proxyHost );
723 connection +=
':' + QString::number( proxyPort );
725 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
726 if ( ! proxyUser.isEmpty( ) )
728 QString credentials( proxyUser );
729 if ( ! proxyPassword.isEmpty( ) )
731 credentials +=
':' + proxyPassword;
733 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
742 const QFileInfo info( path );
743 const long long size = info.size();
749 const QString suffix = info.suffix().toLower();
750 static const QStringList sFileSizeDependentExtensions
756 if ( sFileSizeDependentExtensions.contains( suffix ) )
759 return size < smallFileSizeLimit;
769#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
771 static std::once_flag initialized;
772 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
773 std::call_once( initialized, []
777 GDALDriverH driver =
nullptr;
779 QSet< QString > extensions;
781 for (
int i = 0; i < GDALGetDriverCount(); ++i )
783 driver = GDALGetDriver( i );
790 bool isMultiLayer =
false;
791 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) ==
"YES"_L1 )
793 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
798 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) ==
"YES"_L1 )
800 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
809 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
810 if ( driverExtensions.isEmpty() )
813 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
815 for (
const QString &ext : splitExtensions )
818 if ( ext ==
"tif"_L1 || ext ==
"tiff"_L1 )
821 extensions.insert( ext );
825 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
827 return SUPPORTED_DB_LAYERS_EXTENSIONS;
830 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
852 return SUPPORTED_DB_LAYERS_EXTENSIONS;
860 const thread_local QRegularExpression vsiRx( u
"^(/vsi.+?/)"_s, QRegularExpression::PatternOption::CaseInsensitiveOption );
861 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
862 if ( vsiMatch.hasMatch() )
863 return vsiMatch.captured( 1 );
865 if ( path.endsWith(
".shp.zip"_L1, Qt::CaseInsensitive ) ||
866 path.endsWith(
".gdb.zip"_L1, Qt::CaseInsensitive ) )
869 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
871 return u
"/vsizip/"_s;
873 else if ( path.endsWith(
".zip"_L1, Qt::CaseInsensitive ) )
876 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
877 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
879 return u
"/vsizip/"_s;
881 else if ( path.endsWith(
".tar"_L1, Qt::CaseInsensitive ) ||
882 path.endsWith(
".tar.gz"_L1, Qt::CaseInsensitive ) ||
883 path.endsWith(
".tgz"_L1, Qt::CaseInsensitive ) )
884 return u
"/vsitar/"_s;
885 else if ( path.endsWith(
".gz"_L1, Qt::CaseInsensitive ) )
886 return u
"/vsigzip/"_s;
887#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
888 else if ( vsiPrefixes.contains( u
"/vsi7z/"_s ) &&
889 ( path.endsWith(
".7z"_L1, Qt::CaseInsensitive ) ||
890 path.endsWith(
".lpk"_L1, Qt::CaseInsensitive ) ||
891 path.endsWith(
".lpkx"_L1, Qt::CaseInsensitive ) ||
892 path.endsWith(
".mpk"_L1, Qt::CaseInsensitive ) ||
893 path.endsWith(
".mpkx"_L1, Qt::CaseInsensitive ) ) )
895 else if ( vsiPrefixes.contains( u
"/vsirar/"_s ) &&
896 path.endsWith(
".rar"_L1, Qt::CaseInsensitive ) )
897 return u
"/vsirar/"_s;
905 QStringList res { u
"/vsizip/"_s,
909#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
910 res.append( u
"/vsi7z/"_s );
911 res.append( u
"/vsirar/"_s );
919 static std::once_flag initialized;
920 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
921 std::call_once( initialized, []
923 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
925 for (
int i = 0; papszPrefixes[i]; i++ )
928 details.
identifier = QString( papszPrefixes[i] );
935 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
937 details.
name = QObject::tr(
"AWS S3" );
939 details.
name = QObject::tr(
"Google Cloud Storage" );
941 details.
name = QObject::tr(
"Microsoft Azure Blob" );
942 else if ( details.
identifier ==
"vsiadls"_L1 )
943 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
945 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
946 else if ( details.
identifier ==
"vsiswift"_L1 )
947 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
948 else if ( details.
identifier ==
"vsihdfs"_L1 )
949 details.
name = QObject::tr(
"Hadoop File System" );
952 VSI_FILE_SYSTEM_DETAILS.append( details );
955 CSLDestroy( papszPrefixes );
959 return VSI_FILE_SYSTEM_DETAILS;
965 for (
const QString &archivePrefix : prefixes )
968 if ( prefix.contains( archivePrefix ) )
976 QStringList res { u
".zip"_s,
982#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
983 res.append( { u
".7z"_s,
996 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
1002 if ( prefix.isEmpty() )
1005 QString vsiPrefix = prefix;
1006 if ( vsiPrefix.startsWith(
'/' ) )
1007 vsiPrefix = vsiPrefix.mid( 1 );
1008 if ( vsiPrefix.endsWith(
'/' ) )
1009 vsiPrefix.chop( 1 );
1011 if ( !vsiPrefix.startsWith(
"vsi"_L1 ) )
1014 if ( vsiPrefix ==
"vsizip"_L1 ||
1015 vsiPrefix ==
"vsigzip"_L1 ||
1016 vsiPrefix ==
"vsitar"_L1 ||
1017 vsiPrefix ==
"vsi7z"_L1 ||
1018 vsiPrefix ==
"vsirar"_L1 )
1021 else if ( vsiPrefix ==
"vsicurl"_L1 ||
1022 vsiPrefix ==
"vsicurl_streaming"_L1 )
1025 else if ( vsiPrefix ==
"vsis3"_L1 ||
1026 vsiPrefix ==
"vsicurl_streaming"_L1 ||
1027 vsiPrefix ==
"vsigs"_L1 ||
1028 vsiPrefix ==
"vsigs_streaming"_L1 ||
1029 vsiPrefix ==
"vsiaz"_L1 ||
1030 vsiPrefix ==
"vsiaz_streaming"_L1 ||
1031 vsiPrefix ==
"vsiadls"_L1 ||
1032 vsiPrefix ==
"vsioss"_L1 ||
1033 vsiPrefix ==
"vsioss_streaming"_L1 ||
1034 vsiPrefix ==
"vsiswift"_L1 ||
1035 vsiPrefix ==
"vsiswift_streaming"_L1 ||
1036 vsiPrefix ==
"vsihdfs"_L1 ||
1037 vsiPrefix ==
"vsiwebhdfs"_L1 )
1040 else if ( vsiPrefix ==
"vsimem"_L1 )
1048 CPLPushErrorHandler( CPLQuietErrorHandler );
1050 GDALDriverH hDriver =
nullptr;
1055 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
1059 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1072 CPLPopErrorHandler();
1073 return static_cast< bool >( hDriver );
1080 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1081 if ( !gdalDriverHelpTopic.isEmpty() )
1082 return u
"https://gdal.org/%1"_s.arg( gdalDriverHelpTopic );
1089 QString vsiPrefix = prefix;
1090 if ( !vsiPrefix.startsWith(
'/' ) )
1091 vsiPrefix.prepend(
'/' );
1092 if ( !vsiPrefix.endsWith(
'/' ) )
1093 vsiPrefix.append(
'/' );
1095 QString vsiPath = path;
1096 if ( vsiPath.endsWith(
'/' ) )
1099 const QString bucket = vsiPrefix + vsiPath;
1101 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1103#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0)
1104 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1105#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 5, 0)
1106 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1124 void *pProgressArg )
1130 feedback->setProgress( adapter->mStartPercentage +
1131 ( adapter->mEndPercentage - adapter->mStartPercentage ) * dfComplete );
1133 if ( feedback->isCanceled() )
VsiHandlerType
GDAL VSI handler types.
@ Memory
In-memory types (e.g. vsimem).
@ Invalid
Invalid type, i.e. not a valid VSI handler.
@ Cloud
Specific cloud provider types (e.g. vsis3).
@ Archive
File archive type (e.g. vsizip).
@ Network
Generic network types (e.g. vsicurl).
RasterResamplingMethod
Resampling method for raster 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.
@ Average
Average resampling.
@ CubicSpline
Cubic B-Spline Approximation (4x4 kernel).
@ Cubic
Cubic Convolution Approximation (4x4 kernel) resampling.
@ Critical
Critical/error message.
DataType
Raster data types.
@ 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.
@ UInt32
Thirty two bit unsigned integer (quint32).
LayerType
Types of layers that can be added to a map.
@ 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.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ PreferredGdal
Preferred format for conversion of CRS to WKT for use with the GDAL library.
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.
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Encapsulates the definition of a GDAL configuration option.
QVariant defaultValue
Default value.
QVariant maximum
Maximum acceptable value.
QStringList options
Available choices, for Select options.
QVariant minimum
Minimum acceptable value.
@ 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.
QgsGdalProgressAdapter(QgsFeedback *feedback, double startPercentage=0.0, double endPercentage=100.0)
Constructor from feedback (which may be NULL).
static int CPL_STDCALL progressCallback(double dfComplete, const char *pszMessage, void *pProgressArg)
GDAL progress callback.
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.
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.
Stores settings for use within QGIS.
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.
#define QgsDebugError(str)
Encapsulates details for a GDAL VSI network file system.
QString name
Translated, user-friendly name.
QString identifier
VSI handler identifier, eg "vsis3".