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
677 if ( !proxies.isEmpty() )
679 const QNetworkProxy proxy( proxies.first() );
682 const QString proxyHost( proxy.hostName() );
683 const quint16 proxyPort( proxy.port() );
685 const QString proxyUser( proxy.user() );
686 const QString proxyPassword( proxy.password() );
688 if ( !proxyHost.isEmpty() )
690 QString connection( proxyHost );
693 connection +=
':' + QString::number( proxyPort );
695 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
696 if ( !proxyUser.isEmpty() )
698 QString credentials( proxyUser );
699 if ( !proxyPassword.isEmpty() )
701 credentials +=
':' + proxyPassword;
703 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
712 const QFileInfo info( path );
713 const long long size = info.size();
719 const QString suffix = info.suffix().toLower();
720 static const QStringList sFileSizeDependentExtensions { u
"xlsx"_s, u
"ods"_s, u
"csv"_s };
721 if ( sFileSizeDependentExtensions.contains( suffix ) )
724 return size < smallFileSizeLimit;
734#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 4, 0 )
736 static std::once_flag initialized;
737 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
738 std::call_once( initialized, [] {
741 GDALDriverH driver =
nullptr;
743 QSet< QString > extensions;
745 for (
int i = 0; i < GDALGetDriverCount(); ++i )
747 driver = GDALGetDriver( i );
754 bool isMultiLayer =
false;
755 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) ==
"YES"_L1 )
757 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
762 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) ==
"YES"_L1 )
764 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
773 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
774 if ( driverExtensions.isEmpty() )
777 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
779 for (
const QString &ext : splitExtensions )
782 if ( ext ==
"tif"_L1 || ext ==
"tiff"_L1 )
785 extensions.insert( ext );
789 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
791 return SUPPORTED_DB_LAYERS_EXTENSIONS;
794 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,
795 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 };
796 return SUPPORTED_DB_LAYERS_EXTENSIONS;
804 const thread_local QRegularExpression vsiRx( u
"^(/vsi.+?/)"_s, QRegularExpression::PatternOption::CaseInsensitiveOption );
805 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
806 if ( vsiMatch.hasMatch() )
807 return vsiMatch.captured( 1 );
809 if ( path.endsWith(
".shp.zip"_L1, Qt::CaseInsensitive ) || path.endsWith(
".gdb.zip"_L1, Qt::CaseInsensitive ) )
812 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
814 return u
"/vsizip/"_s;
816 else if ( path.endsWith(
".zip"_L1, Qt::CaseInsensitive ) )
819 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
820 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
822 return u
"/vsizip/"_s;
824 else if ( path.endsWith(
".tar"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tar.gz"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tgz"_L1, Qt::CaseInsensitive ) )
825 return u
"/vsitar/"_s;
826 else if ( path.endsWith(
".gz"_L1, Qt::CaseInsensitive ) )
827 return u
"/vsigzip/"_s;
828#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
829 else if ( vsiPrefixes.contains( u
"/vsi7z/"_s ) &&
830 ( path.endsWith(
".7z"_L1, Qt::CaseInsensitive ) ||
831 path.endsWith(
".lpk"_L1, Qt::CaseInsensitive ) ||
832 path.endsWith(
".lpkx"_L1, Qt::CaseInsensitive ) ||
833 path.endsWith(
".mpk"_L1, Qt::CaseInsensitive ) ||
834 path.endsWith(
".mpkx"_L1, Qt::CaseInsensitive ) ) )
836 else if ( vsiPrefixes.contains( u
"/vsirar/"_s ) && path.endsWith(
".rar"_L1, Qt::CaseInsensitive ) )
837 return u
"/vsirar/"_s;
850#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
851 res.append( u
"/vsi7z/"_s );
852 res.append( u
"/vsirar/"_s );
860 static std::once_flag initialized;
861 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
862 std::call_once( initialized, [] {
863 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
865 for (
int i = 0; papszPrefixes[i]; i++ )
868 details.
identifier = QString( papszPrefixes[i] );
875 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
877 details.
name = QObject::tr(
"AWS S3" );
879 details.
name = QObject::tr(
"Google Cloud Storage" );
881 details.
name = QObject::tr(
"Microsoft Azure Blob" );
882 else if ( details.
identifier ==
"vsiadls"_L1 )
883 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
885 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
886 else if ( details.
identifier ==
"vsiswift"_L1 )
887 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
888 else if ( details.
identifier ==
"vsihdfs"_L1 )
889 details.
name = QObject::tr(
"Hadoop File System" );
892 VSI_FILE_SYSTEM_DETAILS.append( details );
895 CSLDestroy( papszPrefixes );
899 return VSI_FILE_SYSTEM_DETAILS;
905 for (
const QString &archivePrefix : prefixes )
908 if ( prefix.contains( archivePrefix ) )
923#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
924 res.append( { u
".7z"_s, u
".lpk"_s, u
".lpkx"_s, u
".mpk"_s, u
".mpkx"_s, u
".rar"_s } );
931 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
937 if ( prefix.isEmpty() )
940 QString vsiPrefix = prefix;
941 if ( vsiPrefix.startsWith(
'/' ) )
942 vsiPrefix = vsiPrefix.mid( 1 );
943 if ( vsiPrefix.endsWith(
'/' ) )
946 if ( !vsiPrefix.startsWith(
"vsi"_L1 ) )
949 if ( vsiPrefix ==
"vsizip"_L1 || vsiPrefix ==
"vsigzip"_L1 || vsiPrefix ==
"vsitar"_L1 || vsiPrefix ==
"vsi7z"_L1 || vsiPrefix ==
"vsirar"_L1 )
952 else if ( vsiPrefix ==
"vsicurl"_L1 || vsiPrefix ==
"vsicurl_streaming"_L1 )
955 else if ( vsiPrefix ==
"vsis3"_L1
956 || vsiPrefix ==
"vsicurl_streaming"_L1
957 || vsiPrefix ==
"vsigs"_L1
958 || vsiPrefix ==
"vsigs_streaming"_L1
959 || vsiPrefix ==
"vsiaz"_L1
960 || vsiPrefix ==
"vsiaz_streaming"_L1
961 || vsiPrefix ==
"vsiadls"_L1
962 || vsiPrefix ==
"vsioss"_L1
963 || vsiPrefix ==
"vsioss_streaming"_L1
964 || vsiPrefix ==
"vsiswift"_L1
965 || vsiPrefix ==
"vsiswift_streaming"_L1
966 || vsiPrefix ==
"vsihdfs"_L1
967 || vsiPrefix ==
"vsiwebhdfs"_L1 )
970 else if ( vsiPrefix ==
"vsimem"_L1 )
978 CPLPushErrorHandler( CPLQuietErrorHandler );
980 GDALDriverH hDriver =
nullptr;
985 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
989 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1002 CPLPopErrorHandler();
1003 return static_cast< bool >( hDriver );
1010 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1011 if ( !gdalDriverHelpTopic.isEmpty() )
1012 return u
"https://gdal.org/%1"_s.arg( gdalDriverHelpTopic );
1019 GDALDriverH hDriver = GDALGetDriverByName(
"MRF" );
1022 const char *creationOptions = GDALGetMetadataItem( hDriver, GDAL_DMD_CREATIONOPTIONLIST, NULL );
1023 if ( creationOptions && strstr( creationOptions,
"LERC" ) )
1033 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
1036 const char *creationOptions = GDALGetMetadataItem( hDriver, GDAL_DMD_CREATIONOPTIONLIST, NULL );
1037 if ( creationOptions && strstr( creationOptions,
"LERC" ) )
1047 QString vsiPrefix = prefix;
1048 if ( !vsiPrefix.startsWith(
'/' ) )
1049 vsiPrefix.prepend(
'/' );
1050 if ( !vsiPrefix.endsWith(
'/' ) )
1051 vsiPrefix.append(
'/' );
1053 QString vsiPath = path;
1054 if ( vsiPath.endsWith(
'/' ) )
1057 const QString bucket = vsiPrefix + vsiPath;
1059 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1061#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
1062 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1063#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 5, 0 )
1064 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1076 : mFeedback( feedback )
1077 , mStartPercentage( startPercentage )
1078 , mEndPercentage( endPercentage )
1088 feedback->setProgress( adapter->mStartPercentage + ( adapter->mEndPercentage - adapter->mStartPercentage ) * dfComplete );
1090 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 supportsTiffLercCompression()
Returns true if the GDAL library used by this QGIS install supports the LERC compression technique fo...
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 bool supportsMrfLercCompression()
Returns true if the GDAL library used by this QGIS install supports the LERC compression technique fo...
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 const QgsSettingsEntryBool * settingsProxyEnabled
Settings entry for whether proxy is enabled.
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.
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".