24#define CPL_SUPRESS_CPLUSPLUS
26#include "gdalwarper.h"
27#include "cpl_string.h"
29#include <QNetworkProxy>
38 if ( node->eType != CXT_Element || !EQUAL( node->pszValue,
"Option" ) )
41 const QString optionName( CPLGetXMLValue( node,
"name",
nullptr ) );
42 if ( optionName.isEmpty() )
46 option.
name = optionName;
48 option.
description = QString( CPLGetXMLValue( node,
"description",
nullptr ) );
49 option.
scope = QString( CPLGetXMLValue( node,
"scope",
nullptr ) );
53 const char *pszType = CPLGetXMLValue( node,
"type",
nullptr );
54 const char *pszDefault = CPLGetXMLValue( node,
"default",
nullptr );
55 if ( pszType && EQUAL( pszType,
"string-select" ) )
58 for (
auto psOption = node->psChild; psOption !=
nullptr; psOption = psOption->psNext )
60 if ( psOption->eType != CXT_Element ||
61 !EQUAL( psOption->pszValue,
"Value" ) ||
66 option.
options << psOption->psChild->pszValue;
71 else if ( pszType && EQUAL( pszType,
"boolean" ) )
74 option.
defaultValue = pszDefault ? QString( pszDefault ) : QStringLiteral(
"YES" );
77 else if ( pszType && EQUAL( pszType,
"string" ) )
84 else if ( pszType && ( EQUAL( pszType,
"int" ) || EQUAL( pszType,
"integer" ) ) )
90 const int defaultInt = QString( pszDefault ).toInt( &ok );
95 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
98 const int minInt = QString( pszMin ).toInt( &ok );
102 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
105 const int maxInt = QString( pszMax ).toInt( &ok );
111 else if ( pszType && EQUAL( pszType,
"double" ) )
117 const double defaultDouble = QString( pszDefault ).toDouble( &ok );
122 if (
const char *pszMin = CPLGetXMLValue( node,
"min",
nullptr ) )
125 const double minDouble = QString( pszMin ).toDouble( &ok );
129 if (
const char *pszMax = CPLGetXMLValue( node,
"max",
nullptr ) )
132 const double maxDouble = QString( pszMax ).toDouble( &ok );
139 QgsDebugError( QStringLiteral(
"Unhandled GDAL option type: %1" ).arg( pszType ) );
145 QList< QgsGdalOption >
options;
146 for (
auto psItem = node->psChild; psItem !=
nullptr; psItem = psItem->psNext )
164 const QString driverShortName = GDALGetDriverShortName( driver );
165 if ( driverShortName == QLatin1String(
"SQLite" ) ||
166 driverShortName == QLatin1String(
"PDF" ) )
171 return GDALGetMetadataItem( driver, GDAL_DCAP_CREATE,
nullptr ) &&
172 GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr );
182 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
190 const double cellSizeX = extent.
width() / width;
191 const double cellSizeY = extent.
height() / height;
192 double geoTransform[6];
193 geoTransform[0] = extent.
xMinimum();
194 geoTransform[1] = cellSizeX;
196 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
198 geoTransform[5] = -cellSizeY;
201 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
207 const double cellSizeX = extent.
width() / width;
208 const double cellSizeY = extent.
height() / height;
209 double geoTransform[6];
210 geoTransform[0] = extent.
xMinimum();
211 geoTransform[1] = cellSizeX;
213 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
215 geoTransform[5] = -cellSizeY;
217 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
224 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toUtf8().constData(), width, height, 1, dataType,
nullptr ) );
232 GDALSetGeoTransform( hDstDS.get(), geoTransform );
238 if ( image.isNull() )
241 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( image.constBits() );
242 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
247 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem,
"", image.width(), image.height(), 0, GDT_Byte,
nullptr ) );
250 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
251 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
252 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 2 ) );
253 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
254 CSLDestroy( papszOptions );
257 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
258 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
259 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 1 ) );
260 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
261 CSLDestroy( papszOptions );
264 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
265 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
266 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) ) );
267 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
268 CSLDestroy( papszOptions );
271 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
272 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
273 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 3 ) );
274 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
275 CSLDestroy( papszOptions );
285 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
289 const double cellSizeX = extent.
width() / pixelWidth;
290 const double cellSizeY = extent.
height() / pixelHeight;
291 double geoTransform[6];
292 geoTransform[0] = extent.
xMinimum();
293 geoTransform[1] = cellSizeX;
295 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * pixelHeight );
297 geoTransform[5] = -cellSizeY;
301 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
303 << QStringLiteral(
"PIXELOFFSET=%1" ).arg( dataTypeSize )
304 << QStringLiteral(
"LINEOFFSET=%1" ).arg( pixelWidth * dataTypeSize )
305 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( block ) ) );
306 GDALAddBand( hDstDS.get(), dataType, papszOptions );
307 CSLDestroy( papszOptions );
309 GDALSetGeoTransform( hDstDS.get(), geoTransform );
322 GDALRasterBandH band = GDALGetRasterBand( ret.get(), 1 );
324 GDALSetRasterNoDataValue( band, block->
noDataValue() );
341 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
345 const double cellSizeX = gridXSize / block->
width();
346 const double cellSizeY = gridYSize / block->
height();
347 double geoTransform[6];
348 geoTransform[0] = origin.
x();
349 geoTransform[1] = cellSizeX * std::cos( rotation );
350 geoTransform[2] = cellSizeY * std::sin( rotation );
351 geoTransform[3] = origin.
y();
352 geoTransform[4] = cellSizeX * std::sin( rotation );
353 geoTransform[5] = -cellSizeY * std::cos( rotation );
358 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
360 << QStringLiteral(
"PIXELOFFSET=%1" ).arg( dataTypeSize )
361 << QStringLiteral(
"LINEOFFSET=%1" ).arg( block->
width() * dataTypeSize )
362 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( block->
bits() ) ) );
363 GDALAddBand( hDstDS.get(), dataType, papszOptions );
364 CSLDestroy( papszOptions );
366 GDALSetGeoTransform( hDstDS.get(), geoTransform );
368 GDALRasterBandH band = GDALGetRasterBand( hDstDS.get(), 1 );
370 GDALSetRasterNoDataValue( band, block->
noDataValue() );
375static bool resampleSingleBandRasterStatic(
GDALDatasetH hSrcDS,
GDALDatasetH hDstDS, GDALResampleAlg resampleAlg,
char **papszOptions )
378 psWarpOptions->hSrcDS = hSrcDS;
379 psWarpOptions->hDstDS = hDstDS;
381 psWarpOptions->nBandCount = 1;
382 psWarpOptions->panSrcBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
383 psWarpOptions->panDstBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
384 psWarpOptions->panSrcBands[0] = 1;
385 psWarpOptions->panDstBands[0] = 1;
386 double noDataValue = GDALGetRasterNoDataValue( GDALGetRasterBand( hDstDS, 1 ),
nullptr );
387 psWarpOptions->padfDstNoDataReal =
reinterpret_cast< double *
>( CPLMalloc(
sizeof(
double ) * 1 ) );
388 psWarpOptions->padfDstNoDataReal[0] = noDataValue;
389 psWarpOptions->eResampleAlg = resampleAlg;
392 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
394 if ( ! psWarpOptions->pTransformerArg )
399 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
400 psWarpOptions->papszWarpOptions = CSLSetNameValue( psWarpOptions-> papszWarpOptions,
"INIT_DEST",
"NO_DATA" );
404 GDALWarpOperation oOperation;
405 CPLErr initResult = oOperation.Initialize( psWarpOptions.get() );
406 if ( initResult != CE_Failure )
407 retVal = oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None;
408 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
414 char **papszOptions =
nullptr;
415 if ( pszCoordinateOperation )
416 papszOptions = CSLSetNameValue( papszOptions,
"COORDINATE_OPERATION", pszCoordinateOperation );
418 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
419 CSLDestroy( papszOptions );
425 GDALResampleAlg resampleAlg,
429 char **papszOptions =
nullptr;
434 bool result = resampleSingleBandRasterStatic( hSrcDS, hDstDS, resampleAlg, papszOptions );
435 CSLDestroy( papszOptions );
445 GDALRasterIOExtraArg extra;
446 INIT_RASTERIO_EXTRA_ARG( extra );
447 extra.eResampleAlg = resampleAlg;
449 QImage res( outputSize, image.format() );
453 GByte *rgb =
reinterpret_cast<GByte *
>( res.bits() );
455 CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
456 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
457 if ( err != CE_None )
459 QgsDebugError( QStringLiteral(
"failed to read red band" ) );
463 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
464 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
465 if ( err != CE_None )
467 QgsDebugError( QStringLiteral(
"failed to read green band" ) );
471 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
472 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
473 if ( err != CE_None )
475 QgsDebugError( QStringLiteral(
"failed to read blue band" ) );
479 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
480 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
481 if ( err != CE_None )
483 QgsDebugError( QStringLiteral(
"failed to read alpha band" ) );
493 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
497 char **GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
498 message += QLatin1String(
"Format Details:\n" );
499 message += QStringLiteral(
" Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
500 message += QStringLiteral(
" Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
501 message += QStringLiteral(
" / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
503 if ( !helpUrl.isEmpty() )
504 message += QStringLiteral(
" Help page: %1\n\n" ).arg( helpUrl );
508 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
509 GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
510 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
511 if ( pszFormattedXML )
512 message += QString( pszFormattedXML );
514 CPLDestroyXMLNode( psCOL );
515 if ( pszFormattedXML )
516 CPLFree( pszFormattedXML );
523 char **papszRetList =
nullptr;
524 const auto constList = list;
525 for (
const QString &elem : constList )
527 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
534 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
535 if ( ! myGdalDriver )
536 return QStringLiteral(
"invalid GDAL driver" );
540 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
541 CSLDestroy( papszOptions );
544 return QStringLiteral(
"Failed GDALValidateCreationOptions() test" );
550 const char *pszSrcWKT,
551 const char *pszDstWKT,
552 GDALResampleAlg eResampleAlg,
554 const GDALWarpOptions *psOptionsIn )
556 char **opts =
nullptr;
557 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
560 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
562 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
565 return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
570 char **opts = CSLDuplicate( papszOptions );
571 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
574 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
576 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
578 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
588 return GDALDataType::GDT_Unknown;
591 return GDALDataType::GDT_Byte;
594#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
595 return GDALDataType::GDT_Int8;
597 return GDALDataType::GDT_Unknown;
601 return GDALDataType::GDT_UInt16;
604 return GDALDataType::GDT_Int16;
607 return GDALDataType::GDT_UInt32;
610 return GDALDataType::GDT_Int32;
613 return GDALDataType::GDT_Float32;
616 return GDALDataType::GDT_Float64;
619 return GDALDataType::GDT_CInt16;
622 return GDALDataType::GDT_CInt32;
625 return GDALDataType::GDT_CFloat32;
628 return GDALDataType::GDT_CFloat64;
632 return GDALDataType::GDT_Unknown;
636 return GDALDataType::GDT_Unknown;
641 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
646 eResampleAlg = GRA_NearestNeighbour;
650 eResampleAlg = GRA_Bilinear;
654 eResampleAlg = GRA_Cubic;
658 eResampleAlg = GRA_CubicSpline;
662 eResampleAlg = GRA_Lanczos;
666 eResampleAlg = GRA_Average;
670 eResampleAlg = GRA_Mode;
677#ifndef QT_NO_NETWORKPROXY
687 if ( settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool() )
691 if ( ! proxies.isEmpty() )
693 const QNetworkProxy proxy( proxies.first() );
698 const QString proxyHost( proxy.hostName() );
699 const quint16 proxyPort( proxy.port() );
701 const QString proxyUser( proxy.user() );
702 const QString proxyPassword( proxy.password() );
704 if ( ! proxyHost.isEmpty() )
706 QString connection( proxyHost );
709 connection +=
':' + QString::number( proxyPort );
711 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
712 if ( ! proxyUser.isEmpty( ) )
714 QString credentials( proxyUser );
715 if ( ! proxyPassword.isEmpty( ) )
717 credentials +=
':' + proxyPassword;
719 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
728 const QFileInfo info( path );
729 const long long size = info.size();
735 const QString suffix = info.suffix().toLower();
736 static const QStringList sFileSizeDependentExtensions
738 QStringLiteral(
"xlsx" ),
739 QStringLiteral(
"ods" ),
740 QStringLiteral(
"csv" )
742 if ( sFileSizeDependentExtensions.contains( suffix ) )
745 return size < smallFileSizeLimit;
755#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
757 static std::once_flag initialized;
758 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
759 std::call_once( initialized, [ = ]
763 GDALDriverH driver =
nullptr;
765 QSet< QString > extensions;
767 for (
int i = 0; i < GDALGetDriverCount(); ++i )
769 driver = GDALGetDriver( i );
776 bool isMultiLayer =
false;
777 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) == QLatin1String(
"YES" ) )
779 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
784 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) == QLatin1String(
"YES" ) )
786 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
795 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
796 if ( driverExtensions.isEmpty() )
799 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
801 for (
const QString &ext : splitExtensions )
804 if ( ext == QLatin1String(
"tif" ) || ext == QLatin1String(
"tiff" ) )
807 extensions.insert( ext );
811 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
813 return SUPPORTED_DB_LAYERS_EXTENSIONS;
816 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
818 QStringLiteral(
"gpkg" ),
819 QStringLiteral(
"sqlite" ),
820 QStringLiteral(
"db" ),
821 QStringLiteral(
"gdb" ),
822 QStringLiteral(
"kml" ),
823 QStringLiteral(
"kmz" ),
824 QStringLiteral(
"osm" ),
825 QStringLiteral(
"mdb" ),
826 QStringLiteral(
"accdb" ),
827 QStringLiteral(
"xls" ),
828 QStringLiteral(
"xlsx" ),
829 QStringLiteral(
"ods" ),
830 QStringLiteral(
"gpx" ),
831 QStringLiteral(
"pdf" ),
832 QStringLiteral(
"pbf" ),
833 QStringLiteral(
"vrt" ),
834 QStringLiteral(
"nc" ),
835 QStringLiteral(
"dxf" ),
836 QStringLiteral(
"shp.zip" ) };
837 return SUPPORTED_DB_LAYERS_EXTENSIONS;
845 const thread_local QRegularExpression vsiRx( QStringLiteral(
"^(/vsi.+?/)" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
846 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
847 if ( vsiMatch.hasMatch() )
848 return vsiMatch.captured( 1 );
850 if ( path.endsWith( QLatin1String(
".shp.zip" ), Qt::CaseInsensitive ) )
853 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
855 return QStringLiteral(
"/vsizip/" );
857 else if ( path.endsWith( QLatin1String(
".zip" ), Qt::CaseInsensitive ) )
860 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
861 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
863 return QStringLiteral(
"/vsizip/" );
865 else if ( path.endsWith( QLatin1String(
".tar" ), Qt::CaseInsensitive ) ||
866 path.endsWith( QLatin1String(
".tar.gz" ), Qt::CaseInsensitive ) ||
867 path.endsWith( QLatin1String(
".tgz" ), Qt::CaseInsensitive ) )
868 return QStringLiteral(
"/vsitar/" );
869 else if ( path.endsWith( QLatin1String(
".gz" ), Qt::CaseInsensitive ) )
870 return QStringLiteral(
"/vsigzip/" );
871#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
872 else if ( vsiPrefixes.contains( QStringLiteral(
"/vsi7z/" ) ) &&
873 ( path.endsWith( QLatin1String(
".7z" ), Qt::CaseInsensitive ) ||
874 path.endsWith( QLatin1String(
".lpk" ), Qt::CaseInsensitive ) ||
875 path.endsWith( QLatin1String(
".lpkx" ), Qt::CaseInsensitive ) ||
876 path.endsWith( QLatin1String(
".mpk" ), Qt::CaseInsensitive ) ||
877 path.endsWith( QLatin1String(
".mpkx" ), Qt::CaseInsensitive ) ) )
878 return QStringLiteral(
"/vsi7z/" );
879 else if ( vsiPrefixes.contains( QStringLiteral(
"/vsirar/" ) ) &&
880 path.endsWith( QLatin1String(
".rar" ), Qt::CaseInsensitive ) )
881 return QStringLiteral(
"/vsirar/" );
889 QStringList res { QStringLiteral(
"/vsizip/" ),
890 QStringLiteral(
"/vsitar/" ),
891 QStringLiteral(
"/vsigzip/" ),
893#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
894 res.append( QStringLiteral(
"/vsi7z/" ) );
895 res.append( QStringLiteral(
"/vsirar/" ) );
903 static std::once_flag initialized;
904 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
905 std::call_once( initialized, [ = ]
907 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
909 for (
int i = 0; papszPrefixes[i]; i++ )
912 details.
identifier = QString( papszPrefixes[i] );
918 if ( details.
identifier == QLatin1String(
"vsicurl" ) )
919 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
920 else if ( details.
identifier == QLatin1String(
"vsis3" ) )
921 details.
name = QObject::tr(
"AWS S3" );
922 else if ( details.
identifier == QLatin1String(
"vsigs" ) )
923 details.
name = QObject::tr(
"Google Cloud Storage" );
924 else if ( details.
identifier == QLatin1String(
"vsiaz" ) )
925 details.
name = QObject::tr(
"Microsoft Azure Blob" );
926 else if ( details.
identifier == QLatin1String(
"vsiadls" ) )
927 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
928 else if ( details.
identifier == QLatin1String(
"vsioss" ) )
929 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
930 else if ( details.
identifier == QLatin1String(
"vsiswift" ) )
931 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
932 else if ( details.
identifier == QLatin1String(
"vsihdfs" ) )
933 details.
name = QObject::tr(
"Hadoop File System" );
936 VSI_FILE_SYSTEM_DETAILS.append( details );
939 CSLDestroy( papszPrefixes );
943 return VSI_FILE_SYSTEM_DETAILS;
953 QStringList res { QStringLiteral(
".zip" ),
954 QStringLiteral(
".tar" ),
955 QStringLiteral(
".tar.gz" ),
956 QStringLiteral(
".tgz" ),
957 QStringLiteral(
".gz" ),
959#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
960 res.append( { QStringLiteral(
".7z" ),
961 QStringLiteral(
".lpk" ),
962 QStringLiteral(
".lpkx" ),
963 QStringLiteral(
".mpk" ),
964 QStringLiteral(
".mpkx" ),
965 QStringLiteral(
".rar" )
973 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
979 if ( prefix.isEmpty() )
982 QString vsiPrefix = prefix;
983 if ( vsiPrefix.startsWith(
'/' ) )
984 vsiPrefix = vsiPrefix.mid( 1 );
985 if ( vsiPrefix.endsWith(
'/' ) )
988 if ( !vsiPrefix.startsWith( QLatin1String(
"vsi" ) ) )
991 if ( vsiPrefix == QLatin1String(
"vsizip" ) ||
992 vsiPrefix == QLatin1String(
"vsigzip" ) ||
993 vsiPrefix == QLatin1String(
"vsitar" ) ||
994 vsiPrefix == QLatin1String(
"vsi7z" ) ||
995 vsiPrefix == QLatin1String(
"vsirar" ) )
998 else if ( vsiPrefix == QLatin1String(
"vsicurl" ) ||
999 vsiPrefix == QLatin1String(
"vsicurl_streaming" ) )
1002 else if ( vsiPrefix == QLatin1String(
"vsis3" ) ||
1003 vsiPrefix == QLatin1String(
"vsicurl_streaming" ) ||
1004 vsiPrefix == QLatin1String(
"vsigs" ) ||
1005 vsiPrefix == QLatin1String(
"vsigs_streaming" ) ||
1006 vsiPrefix == QLatin1String(
"vsiaz" ) ||
1007 vsiPrefix == QLatin1String(
"vsiaz_streaming" ) ||
1008 vsiPrefix == QLatin1String(
"vsiadls" ) ||
1009 vsiPrefix == QLatin1String(
"vsioss" ) ||
1010 vsiPrefix == QLatin1String(
"vsioss_streaming" ) ||
1011 vsiPrefix == QLatin1String(
"vsiswift" ) ||
1012 vsiPrefix == QLatin1String(
"vsiswift_streaming" ) ||
1013 vsiPrefix == QLatin1String(
"vsihdfs" ) ||
1014 vsiPrefix == QLatin1String(
"vsiwebhdfs" ) )
1017 else if ( vsiPrefix == QLatin1String(
"vsimem" ) )
1025 CPLPushErrorHandler( CPLQuietErrorHandler );
1027 GDALDriverH hDriver =
nullptr;
1032 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
1036 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1049 CPLPopErrorHandler();
1050 return static_cast< bool >( hDriver );
1057 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1058 if ( !gdalDriverHelpTopic.isEmpty() )
1059 return QStringLiteral(
"https://gdal.org/%1" ).arg( gdalDriverHelpTopic );
1066 QString vsiPrefix = prefix;
1067 if ( !vsiPrefix.startsWith(
'/' ) )
1068 vsiPrefix.prepend(
'/' );
1069 if ( !vsiPrefix.endsWith(
'/' ) )
1070 vsiPrefix.append(
'/' );
1072 QString vsiPath = path;
1073 if ( vsiPath.endsWith(
'/' ) )
1076 const QString bucket = vsiPrefix + vsiPath;
1078 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1080#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0)
1081 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1082#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 5, 0)
1083 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
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.
This class represents a coordinate reference system (CRS).
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Encapsulates the definition of a GDAL configuration option.
QVariant defaultValue
Default value.
QVariant maximum
Maximum acceptable value.
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.
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 QString validateCreationOptionsFormat(const QStringList &createOptions, const QString &format)
Validates creation options for a given format, regardless of layer.
static gdal::dataset_unique_ptr blockToSingleBandMemoryDataset(int pixelWidth, int pixelHeight, const QgsRectangle &extent, void *block, GDALDataType dataType)
Converts a data block to a single band GDAL memory dataset.
static QList< VsiNetworkFileSystemDetails > vsiNetworkFileSystems()
Returns a list of available GDAL VSI network file systems.
static gdal::dataset_unique_ptr imageToMemoryDataset(const QImage &image)
Converts an image to a GDAL memory dataset by borrowing image data.
static void * rpcAwareCreateTransformer(GDALDatasetH hSrcDS, GDALDatasetH hDstDS=nullptr, char **papszOptions=nullptr)
This is a wrapper around GDALCreateGenImgProjTransformer2() that takes into account RPC georeferencin...
static void setupProxy()
Sets the gdal proxy variables.
static QStringList vsiArchiveFileExtensions()
Returns a list of file extensions which correspond to archive style containers supported by GDAL (e....
static char ** papszFromStringList(const QStringList &list)
Helper function.
static QImage resampleImage(const QImage &image, QSize outputSize, GDALRIOResampleAlg resampleAlg)
Resamples a QImage image using GDAL resampler.
static gdal::dataset_unique_ptr createMultiBandMemoryDataset(GDALDataType dataType, int bands, const QgsRectangle &extent, int width, int height, const QgsCoordinateReferenceSystem &crs)
Creates a new multi band memory dataset with given parameters.
static QStringList multiLayerFileExtensions()
Returns a list of file extensions which potentially contain multiple layers representing GDAL raster ...
static QStringList vsiArchivePrefixes()
Returns a list of vsi prefixes which correspond to archive style containers (eg vsizip).
static void warning(const QString &msg)
Goes to qWarning.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
A class to represent a 2D point.
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.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
std::unique_ptr< std::remove_pointer< GDALDatasetH >::type, GDALDatasetCloser > dataset_unique_ptr
Scoped GDAL dataset.
std::unique_ptr< GDALWarpOptions, GDALWarpOptionsDeleter > warp_options_unique_ptr
Scoped GDAL warp options.
#define QgsDebugError(str)
const QgsCoordinateReferenceSystem & crs
Encapsulates details for a GDAL VSI network file system.
QString name
Translated, user-friendly name.
QString identifier
VSI handler identifier, eg "vsis3".