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 || !EQUAL( psOption->pszValue,
"Value" ) || !psOption->psChild )
69 option.
options << psOption->psChild->pszValue;
74 else if ( pszType && EQUAL( pszType,
"boolean" ) )
77 option.
defaultValue = pszDefault ? QString( pszDefault ) : u
"YES"_s;
80 else if ( pszType && EQUAL( pszType,
"string" ) )
87 else if ( pszType && ( EQUAL( pszType,
"int" ) || EQUAL( pszType,
"integer" ) ) )
93 const int defaultInt = QString( pszDefault ).toInt( &ok );
98 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
101 const int minInt = QString( pszMin ).toInt( &ok );
105 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
108 const int maxInt = QString( pszMax ).toInt( &ok );
114 else if ( pszType && ( EQUAL( pszType,
"double" ) || EQUAL( pszType,
"float" ) ) )
120 const double defaultDouble = QString( pszDefault ).toDouble( &ok );
125 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
128 const double minDouble = QString( pszMin ).toDouble( &ok );
132 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
135 const double maxDouble = QString( pszMax ).toDouble( &ok );
142 QgsDebugError( u
"Unhandled GDAL option type: %1"_s.arg( pszType ) );
148 QList< QgsGdalOption >
options;
149 for (
auto psItem = node->psChild; psItem !=
nullptr; psItem = psItem->psNext )
167 const QString driverShortName = GDALGetDriverShortName( driver );
168 if ( driverShortName ==
"SQLite"_L1 || driverShortName ==
"PDF"_L1 )
173 return GDALGetMetadataItem( driver, GDAL_DCAP_CREATE,
nullptr ) && GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr );
183 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
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;
197 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
199 geoTransform[5] = -cellSizeY;
202 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
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;
214 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
216 geoTransform[5] = -cellSizeY;
218 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
225 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toUtf8().constData(), width, height, 1, dataType,
nullptr ) );
233 GDALSetGeoTransform( hDstDS.get(), geoTransform );
239 if ( image.isNull() )
242 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( image.constBits() );
243 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
248 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem,
"", image.width(), image.height(), 0, GDT_Byte,
nullptr ) );
251 QStringList() << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) ) << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 2 )
253 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
254 CSLDestroy( papszOptions );
257 QStringList() << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) ) << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 1 )
259 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
260 CSLDestroy( papszOptions );
263 QStringList() << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) ) << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) )
265 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
266 CSLDestroy( papszOptions );
269 QStringList() << u
"PIXELOFFSET=%1"_s.arg(
sizeof( QRgb ) ) << u
"LINEOFFSET=%1"_s.arg( image.bytesPerLine() ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( rgb ) + 3 )
271 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
272 CSLDestroy( papszOptions );
282 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
286 const double cellSizeX = extent.
width() / pixelWidth;
287 const double cellSizeY = extent.
height() / pixelHeight;
288 double geoTransform[6];
289 geoTransform[0] = extent.
xMinimum();
290 geoTransform[1] = cellSizeX;
292 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * pixelHeight );
294 geoTransform[5] = -cellSizeY;
298 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
300 QStringList() << u
"PIXELOFFSET=%1"_s.arg( dataTypeSize ) << u
"LINEOFFSET=%1"_s.arg( pixelWidth * dataTypeSize ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( block ) )
302 GDALAddBand( hDstDS.get(), dataType, papszOptions );
303 CSLDestroy( papszOptions );
305 GDALSetGeoTransform( hDstDS.get(), geoTransform );
318 GDALRasterBandH band = GDALGetRasterBand( ret.get(), 1 );
320 GDALSetRasterNoDataValue( band, block->
noDataValue() );
332 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
336 const double cellSizeX = gridXSize / block->
width();
337 const double cellSizeY = gridYSize / block->
height();
338 double geoTransform[6];
339 geoTransform[0] = origin.
x();
340 geoTransform[1] = cellSizeX * std::cos( rotation );
341 geoTransform[2] = cellSizeY * std::sin( rotation );
342 geoTransform[3] = origin.
y();
343 geoTransform[4] = cellSizeX * std::sin( rotation );
344 geoTransform[5] = -cellSizeY * std::cos( rotation );
349 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
351 QStringList() << u
"PIXELOFFSET=%1"_s.arg( dataTypeSize ) << u
"LINEOFFSET=%1"_s.arg( block->
width() * dataTypeSize ) << u
"DATAPOINTER=%1"_s.arg(
reinterpret_cast< qulonglong
>( block->
bits() ) )
353 GDALAddBand( hDstDS.get(), dataType, papszOptions );
354 CSLDestroy( papszOptions );
356 GDALSetGeoTransform( hDstDS.get(), geoTransform );
358 GDALRasterBandH band = GDALGetRasterBand( hDstDS.get(), 1 );
360 GDALSetRasterNoDataValue( band, block->
noDataValue() );
365static bool resampleSingleBandRasterStatic(
GDALDatasetH hSrcDS,
GDALDatasetH hDstDS, GDALResampleAlg resampleAlg,
char **papszOptions )
368 psWarpOptions->hSrcDS = hSrcDS;
369 psWarpOptions->hDstDS = hDstDS;
371 psWarpOptions->nBandCount = 1;
372 psWarpOptions->panSrcBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
373 psWarpOptions->panDstBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
374 psWarpOptions->panSrcBands[0] = 1;
375 psWarpOptions->panDstBands[0] = 1;
376 double noDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( hDstDS, 1 ),
nullptr );
377 psWarpOptions->padfDstNoDataReal =
reinterpret_cast< double *
>( CPLMalloc(
sizeof(
double ) * 1 ) );
378 psWarpOptions->padfDstNoDataReal[0] = noDataValue;
379 psWarpOptions->padfSrcNoDataReal =
reinterpret_cast< double *
>( CPLMalloc(
sizeof(
double ) * 1 ) );
380 psWarpOptions->padfSrcNoDataReal[0] = noDataValue;
381 psWarpOptions->eResampleAlg = resampleAlg;
384 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
386 if ( !psWarpOptions->pTransformerArg )
391 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
392 psWarpOptions->papszWarpOptions = CSLSetNameValue( psWarpOptions->papszWarpOptions,
"INIT_DEST",
"NO_DATA" );
396 GDALWarpOperation oOperation;
397 CPLErr initResult = oOperation.Initialize( psWarpOptions.get() );
398 if ( initResult != CE_Failure )
399 retVal = oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None;
400 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
406 char **papszOptions =
nullptr;
407 if ( pszCoordinateOperation )
408 papszOptions = CSLSetNameValue( papszOptions,
"COORDINATE_OPERATION", pszCoordinateOperation );
410 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
411 CSLDestroy( papszOptions );
419 char **papszOptions =
nullptr;
424 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
425 CSLDestroy( papszOptions );
435 GDALRasterIOExtraArg extra;
436 INIT_RASTERIO_EXTRA_ARG( extra );
437 extra.eResampleAlg = resampleAlg;
439 QImage res( outputSize, image.format() );
443 GByte *rgb =
reinterpret_cast<GByte *
>( res.bits() );
446 = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(), outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
447 if ( err != CE_None )
453 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(), outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
454 if ( err != CE_None )
460 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(), outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
461 if ( err != CE_None )
467 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(), outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
468 if ( err != CE_None )
480 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
484 CSLConstList GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
485 message +=
"Format Details:\n"_L1;
486 message += u
" Extension: %1\n"_s.arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
487 message += u
" Short Name: %1"_s.arg( GDALGetDriverShortName( myGdalDriver ) );
488 message += u
" / Long Name: %1\n"_s.arg( GDALGetDriverLongName( myGdalDriver ) );
490 if ( !helpUrl.isEmpty() )
491 message += u
" Help page: %1\n\n"_s.arg( helpUrl );
495 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver, GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
496 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
497 if ( pszFormattedXML )
498 message += QString( pszFormattedXML );
500 CPLDestroyXMLNode( psCOL );
501 if ( pszFormattedXML )
502 CPLFree( pszFormattedXML );
509 char **papszRetList =
nullptr;
510 const auto constList = list;
511 for (
const QString &elem : constList )
513 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
520 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
522 return u
"invalid GDAL driver"_s;
526 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
527 CSLDestroy( papszOptions );
530 return u
"Failed GDALValidateCreationOptions() test"_s;
534static void setRPCTransformerOptions(
GDALDatasetH hSrcDS,
char ***opts )
536 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
540 const char *heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_DEFAULT",
"RPC" );
545 heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
548 *opts = CSLAddNameValue( *opts,
"RPC_HEIGHT", heightStr );
554 char **opts =
nullptr;
555 setRPCTransformerOptions( hSrcDS, &opts );
556 GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
563 char **opts = CSLDuplicate( papszOptions );
564 setRPCTransformerOptions( hSrcDS, &opts );
565 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
575 return GDALDataType::GDT_Unknown;
578 return GDALDataType::GDT_Byte;
581#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
582 return GDALDataType::GDT_Int8;
584 return GDALDataType::GDT_Unknown;
588 return GDALDataType::GDT_UInt16;
591 return GDALDataType::GDT_Int16;
594 return GDALDataType::GDT_UInt32;
597 return GDALDataType::GDT_Int32;
600 return GDALDataType::GDT_Float32;
603 return GDALDataType::GDT_Float64;
606 return GDALDataType::GDT_CInt16;
609 return GDALDataType::GDT_CInt32;
612 return GDALDataType::GDT_CFloat32;
615 return GDALDataType::GDT_CFloat64;
619 return GDALDataType::GDT_Unknown;
623 return GDALDataType::GDT_Unknown;
628 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
633 eResampleAlg = GRA_NearestNeighbour;
637 eResampleAlg = GRA_Bilinear;
641 eResampleAlg = GRA_Cubic;
645 eResampleAlg = GRA_CubicSpline;
649 eResampleAlg = GRA_Lanczos;
653 eResampleAlg = GRA_Average;
657 eResampleAlg = GRA_Mode;
664#ifndef QT_NO_NETWORKPROXY
674 if ( settings.
value( u
"proxy/proxyEnabled"_s,
false ).toBool() )
678 if ( !proxies.isEmpty() )
680 const QNetworkProxy proxy( proxies.first() );
685 const QString proxyHost( proxy.hostName() );
686 const quint16 proxyPort( proxy.port() );
688 const QString proxyUser( proxy.user() );
689 const QString proxyPassword( proxy.password() );
691 if ( !proxyHost.isEmpty() )
693 QString connection( proxyHost );
696 connection +=
':' + QString::number( proxyPort );
698 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
699 if ( !proxyUser.isEmpty() )
701 QString credentials( proxyUser );
702 if ( !proxyPassword.isEmpty() )
704 credentials +=
':' + proxyPassword;
706 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
715 const QFileInfo info( path );
716 const long long size = info.size();
722 const QString suffix = info.suffix().toLower();
723 static const QStringList sFileSizeDependentExtensions { u
"xlsx"_s, u
"ods"_s, u
"csv"_s };
724 if ( sFileSizeDependentExtensions.contains( suffix ) )
727 return size < smallFileSizeLimit;
737#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 4, 0 )
739 static std::once_flag initialized;
740 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
741 std::call_once( initialized, [] {
744 GDALDriverH driver =
nullptr;
746 QSet< QString > extensions;
748 for (
int i = 0; i < GDALGetDriverCount(); ++i )
750 driver = GDALGetDriver( i );
757 bool isMultiLayer =
false;
758 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) ==
"YES"_L1 )
760 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
765 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) ==
"YES"_L1 )
767 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
776 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
777 if ( driverExtensions.isEmpty() )
780 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
782 for (
const QString &ext : splitExtensions )
785 if ( ext ==
"tif"_L1 || ext ==
"tiff"_L1 )
788 extensions.insert( ext );
792 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
794 return SUPPORTED_DB_LAYERS_EXTENSIONS;
797 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS { u
"gpkg"_s, u
"sqlite"_s, u
"db"_s, u
"gdb"_s, u
"kml"_s, u
"kmz"_s, u
"osm"_s, u
"mdb"_s, u
"accdb"_s, u
"xls"_s,
798 u
"xlsx"_s, u
"ods"_s, u
"gpx"_s, u
"pdf"_s, u
"pbf"_s, u
"vrt"_s, u
"nc"_s, u
"dxf"_s, u
"shp.zip"_s, u
"gdb.zip"_s };
799 return SUPPORTED_DB_LAYERS_EXTENSIONS;
807 const thread_local QRegularExpression vsiRx( u
"^(/vsi.+?/)"_s, QRegularExpression::PatternOption::CaseInsensitiveOption );
808 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
809 if ( vsiMatch.hasMatch() )
810 return vsiMatch.captured( 1 );
812 if ( path.endsWith(
".shp.zip"_L1, Qt::CaseInsensitive ) || path.endsWith(
".gdb.zip"_L1, Qt::CaseInsensitive ) )
815 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
817 return u
"/vsizip/"_s;
819 else if ( path.endsWith(
".zip"_L1, Qt::CaseInsensitive ) )
822 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
823 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
825 return u
"/vsizip/"_s;
827 else if ( path.endsWith(
".tar"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tar.gz"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tgz"_L1, Qt::CaseInsensitive ) )
828 return u
"/vsitar/"_s;
829 else if ( path.endsWith(
".gz"_L1, Qt::CaseInsensitive ) )
830 return u
"/vsigzip/"_s;
831#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
832 else if ( vsiPrefixes.contains( u
"/vsi7z/"_s ) &&
833 ( path.endsWith(
".7z"_L1, Qt::CaseInsensitive ) ||
834 path.endsWith(
".lpk"_L1, Qt::CaseInsensitive ) ||
835 path.endsWith(
".lpkx"_L1, Qt::CaseInsensitive ) ||
836 path.endsWith(
".mpk"_L1, Qt::CaseInsensitive ) ||
837 path.endsWith(
".mpkx"_L1, Qt::CaseInsensitive ) ) )
839 else if ( vsiPrefixes.contains( u
"/vsirar/"_s ) && path.endsWith(
".rar"_L1, Qt::CaseInsensitive ) )
840 return u
"/vsirar/"_s;
853#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
854 res.append( u
"/vsi7z/"_s );
855 res.append( u
"/vsirar/"_s );
863 static std::once_flag initialized;
864 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
865 std::call_once( initialized, [] {
866 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
868 for (
int i = 0; papszPrefixes[i]; i++ )
871 details.
identifier = QString( papszPrefixes[i] );
878 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
880 details.
name = QObject::tr(
"AWS S3" );
882 details.
name = QObject::tr(
"Google Cloud Storage" );
884 details.
name = QObject::tr(
"Microsoft Azure Blob" );
885 else if ( details.
identifier ==
"vsiadls"_L1 )
886 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
888 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
889 else if ( details.
identifier ==
"vsiswift"_L1 )
890 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
891 else if ( details.
identifier ==
"vsihdfs"_L1 )
892 details.
name = QObject::tr(
"Hadoop File System" );
895 VSI_FILE_SYSTEM_DETAILS.append( details );
898 CSLDestroy( papszPrefixes );
902 return VSI_FILE_SYSTEM_DETAILS;
908 for (
const QString &archivePrefix : prefixes )
911 if ( prefix.contains( archivePrefix ) )
926#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
927 res.append( { u
".7z"_s, u
".lpk"_s, u
".lpkx"_s, u
".mpk"_s, u
".mpkx"_s, u
".rar"_s } );
934 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
940 if ( prefix.isEmpty() )
943 QString vsiPrefix = prefix;
944 if ( vsiPrefix.startsWith(
'/' ) )
945 vsiPrefix = vsiPrefix.mid( 1 );
946 if ( vsiPrefix.endsWith(
'/' ) )
949 if ( !vsiPrefix.startsWith(
"vsi"_L1 ) )
952 if ( vsiPrefix ==
"vsizip"_L1 || vsiPrefix ==
"vsigzip"_L1 || vsiPrefix ==
"vsitar"_L1 || vsiPrefix ==
"vsi7z"_L1 || vsiPrefix ==
"vsirar"_L1 )
955 else if ( vsiPrefix ==
"vsicurl"_L1 || vsiPrefix ==
"vsicurl_streaming"_L1 )
958 else if ( vsiPrefix ==
"vsis3"_L1
959 || vsiPrefix ==
"vsicurl_streaming"_L1
960 || vsiPrefix ==
"vsigs"_L1
961 || vsiPrefix ==
"vsigs_streaming"_L1
962 || vsiPrefix ==
"vsiaz"_L1
963 || vsiPrefix ==
"vsiaz_streaming"_L1
964 || vsiPrefix ==
"vsiadls"_L1
965 || vsiPrefix ==
"vsioss"_L1
966 || vsiPrefix ==
"vsioss_streaming"_L1
967 || vsiPrefix ==
"vsiswift"_L1
968 || vsiPrefix ==
"vsiswift_streaming"_L1
969 || vsiPrefix ==
"vsihdfs"_L1
970 || vsiPrefix ==
"vsiwebhdfs"_L1 )
973 else if ( vsiPrefix ==
"vsimem"_L1 )
981 CPLPushErrorHandler( CPLQuietErrorHandler );
983 GDALDriverH hDriver =
nullptr;
988 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
992 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1005 CPLPopErrorHandler();
1006 return static_cast< bool >( hDriver );
1013 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1014 if ( !gdalDriverHelpTopic.isEmpty() )
1015 return u
"https://gdal.org/%1"_s.arg( gdalDriverHelpTopic );
1022 QString vsiPrefix = prefix;
1023 if ( !vsiPrefix.startsWith(
'/' ) )
1024 vsiPrefix.prepend(
'/' );
1025 if ( !vsiPrefix.endsWith(
'/' ) )
1026 vsiPrefix.append(
'/' );
1028 QString vsiPath = path;
1029 if ( vsiPath.endsWith(
'/' ) )
1032 const QString bucket = vsiPrefix + vsiPath;
1034 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1036#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
1037 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1038#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 5, 0 )
1039 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1051 : mFeedback( feedback )
1052 , mStartPercentage( startPercentage )
1053 , mEndPercentage( endPercentage )
1063 feedback->setProgress( adapter->mStartPercentage + ( adapter->mEndPercentage - adapter->mStartPercentage ) * dfComplete );
1065 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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".