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" ) || EQUAL( pszType,
"float" ) ) )
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" );
548static void setRPCTransformerOptions(
GDALDatasetH hSrcDS,
char ***opts )
550 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
554 const char *heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_AVERAGE",
"RPC" );
559 heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
562 *opts = CSLAddNameValue( *opts,
"RPC_HEIGHT", heightStr );
568 const char *pszSrcWKT,
569 const char *pszDstWKT,
570 GDALResampleAlg eResampleAlg,
572 const GDALWarpOptions *psOptionsIn )
574 char **opts =
nullptr;
575 setRPCTransformerOptions( hSrcDS, &opts );
576 GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
583 char **opts = CSLDuplicate( papszOptions );
584 setRPCTransformerOptions( hSrcDS, &opts );
585 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
595 return GDALDataType::GDT_Unknown;
598 return GDALDataType::GDT_Byte;
601#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
602 return GDALDataType::GDT_Int8;
604 return GDALDataType::GDT_Unknown;
608 return GDALDataType::GDT_UInt16;
611 return GDALDataType::GDT_Int16;
614 return GDALDataType::GDT_UInt32;
617 return GDALDataType::GDT_Int32;
620 return GDALDataType::GDT_Float32;
623 return GDALDataType::GDT_Float64;
626 return GDALDataType::GDT_CInt16;
629 return GDALDataType::GDT_CInt32;
632 return GDALDataType::GDT_CFloat32;
635 return GDALDataType::GDT_CFloat64;
639 return GDALDataType::GDT_Unknown;
643 return GDALDataType::GDT_Unknown;
648 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
653 eResampleAlg = GRA_NearestNeighbour;
657 eResampleAlg = GRA_Bilinear;
661 eResampleAlg = GRA_Cubic;
665 eResampleAlg = GRA_CubicSpline;
669 eResampleAlg = GRA_Lanczos;
673 eResampleAlg = GRA_Average;
677 eResampleAlg = GRA_Mode;
684#ifndef QT_NO_NETWORKPROXY
694 if ( settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool() )
698 if ( ! proxies.isEmpty() )
700 const QNetworkProxy proxy( proxies.first() );
705 const QString proxyHost( proxy.hostName() );
706 const quint16 proxyPort( proxy.port() );
708 const QString proxyUser( proxy.user() );
709 const QString proxyPassword( proxy.password() );
711 if ( ! proxyHost.isEmpty() )
713 QString connection( proxyHost );
716 connection +=
':' + QString::number( proxyPort );
718 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
719 if ( ! proxyUser.isEmpty( ) )
721 QString credentials( proxyUser );
722 if ( ! proxyPassword.isEmpty( ) )
724 credentials +=
':' + proxyPassword;
726 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
735 const QFileInfo info( path );
736 const long long size = info.size();
742 const QString suffix = info.suffix().toLower();
743 static const QStringList sFileSizeDependentExtensions
745 QStringLiteral(
"xlsx" ),
746 QStringLiteral(
"ods" ),
747 QStringLiteral(
"csv" )
749 if ( sFileSizeDependentExtensions.contains( suffix ) )
752 return size < smallFileSizeLimit;
762#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
764 static std::once_flag initialized;
765 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
766 std::call_once( initialized, [ = ]
770 GDALDriverH driver =
nullptr;
772 QSet< QString > extensions;
774 for (
int i = 0; i < GDALGetDriverCount(); ++i )
776 driver = GDALGetDriver( i );
783 bool isMultiLayer =
false;
784 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) == QLatin1String(
"YES" ) )
786 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
791 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) == QLatin1String(
"YES" ) )
793 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
802 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
803 if ( driverExtensions.isEmpty() )
806 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
808 for (
const QString &ext : splitExtensions )
811 if ( ext == QLatin1String(
"tif" ) || ext == QLatin1String(
"tiff" ) )
814 extensions.insert( ext );
818 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
820 return SUPPORTED_DB_LAYERS_EXTENSIONS;
823 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
825 QStringLiteral(
"gpkg" ),
826 QStringLiteral(
"sqlite" ),
827 QStringLiteral(
"db" ),
828 QStringLiteral(
"gdb" ),
829 QStringLiteral(
"kml" ),
830 QStringLiteral(
"kmz" ),
831 QStringLiteral(
"osm" ),
832 QStringLiteral(
"mdb" ),
833 QStringLiteral(
"accdb" ),
834 QStringLiteral(
"xls" ),
835 QStringLiteral(
"xlsx" ),
836 QStringLiteral(
"ods" ),
837 QStringLiteral(
"gpx" ),
838 QStringLiteral(
"pdf" ),
839 QStringLiteral(
"pbf" ),
840 QStringLiteral(
"vrt" ),
841 QStringLiteral(
"nc" ),
842 QStringLiteral(
"dxf" ),
843 QStringLiteral(
"shp.zip" ) };
844 return SUPPORTED_DB_LAYERS_EXTENSIONS;
852 const thread_local QRegularExpression vsiRx( QStringLiteral(
"^(/vsi.+?/)" ), QRegularExpression::PatternOption::CaseInsensitiveOption );
853 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
854 if ( vsiMatch.hasMatch() )
855 return vsiMatch.captured( 1 );
857 if ( path.endsWith( QLatin1String(
".shp.zip" ), Qt::CaseInsensitive ) )
860 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
862 return QStringLiteral(
"/vsizip/" );
864 else if ( path.endsWith( QLatin1String(
".zip" ), Qt::CaseInsensitive ) )
867 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
868 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
870 return QStringLiteral(
"/vsizip/" );
872 else if ( path.endsWith( QLatin1String(
".tar" ), Qt::CaseInsensitive ) ||
873 path.endsWith( QLatin1String(
".tar.gz" ), Qt::CaseInsensitive ) ||
874 path.endsWith( QLatin1String(
".tgz" ), Qt::CaseInsensitive ) )
875 return QStringLiteral(
"/vsitar/" );
876 else if ( path.endsWith( QLatin1String(
".gz" ), Qt::CaseInsensitive ) )
877 return QStringLiteral(
"/vsigzip/" );
878#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
879 else if ( vsiPrefixes.contains( QStringLiteral(
"/vsi7z/" ) ) &&
880 ( path.endsWith( QLatin1String(
".7z" ), Qt::CaseInsensitive ) ||
881 path.endsWith( QLatin1String(
".lpk" ), Qt::CaseInsensitive ) ||
882 path.endsWith( QLatin1String(
".lpkx" ), Qt::CaseInsensitive ) ||
883 path.endsWith( QLatin1String(
".mpk" ), Qt::CaseInsensitive ) ||
884 path.endsWith( QLatin1String(
".mpkx" ), Qt::CaseInsensitive ) ) )
885 return QStringLiteral(
"/vsi7z/" );
886 else if ( vsiPrefixes.contains( QStringLiteral(
"/vsirar/" ) ) &&
887 path.endsWith( QLatin1String(
".rar" ), Qt::CaseInsensitive ) )
888 return QStringLiteral(
"/vsirar/" );
896 QStringList res { QStringLiteral(
"/vsizip/" ),
897 QStringLiteral(
"/vsitar/" ),
898 QStringLiteral(
"/vsigzip/" ),
900#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
901 res.append( QStringLiteral(
"/vsi7z/" ) );
902 res.append( QStringLiteral(
"/vsirar/" ) );
910 static std::once_flag initialized;
911 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
912 std::call_once( initialized, [ = ]
914 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
916 for (
int i = 0; papszPrefixes[i]; i++ )
919 details.
identifier = QString( papszPrefixes[i] );
925 if ( details.
identifier == QLatin1String(
"vsicurl" ) )
926 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
927 else if ( details.
identifier == QLatin1String(
"vsis3" ) )
928 details.
name = QObject::tr(
"AWS S3" );
929 else if ( details.
identifier == QLatin1String(
"vsigs" ) )
930 details.
name = QObject::tr(
"Google Cloud Storage" );
931 else if ( details.
identifier == QLatin1String(
"vsiaz" ) )
932 details.
name = QObject::tr(
"Microsoft Azure Blob" );
933 else if ( details.
identifier == QLatin1String(
"vsiadls" ) )
934 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
935 else if ( details.
identifier == QLatin1String(
"vsioss" ) )
936 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
937 else if ( details.
identifier == QLatin1String(
"vsiswift" ) )
938 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
939 else if ( details.
identifier == QLatin1String(
"vsihdfs" ) )
940 details.
name = QObject::tr(
"Hadoop File System" );
943 VSI_FILE_SYSTEM_DETAILS.append( details );
946 CSLDestroy( papszPrefixes );
950 return VSI_FILE_SYSTEM_DETAILS;
960 QStringList res { QStringLiteral(
".zip" ),
961 QStringLiteral(
".tar" ),
962 QStringLiteral(
".tar.gz" ),
963 QStringLiteral(
".tgz" ),
964 QStringLiteral(
".gz" ),
966#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,7,0)
967 res.append( { QStringLiteral(
".7z" ),
968 QStringLiteral(
".lpk" ),
969 QStringLiteral(
".lpkx" ),
970 QStringLiteral(
".mpk" ),
971 QStringLiteral(
".mpkx" ),
972 QStringLiteral(
".rar" )
980 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
986 if ( prefix.isEmpty() )
989 QString vsiPrefix = prefix;
990 if ( vsiPrefix.startsWith(
'/' ) )
991 vsiPrefix = vsiPrefix.mid( 1 );
992 if ( vsiPrefix.endsWith(
'/' ) )
995 if ( !vsiPrefix.startsWith( QLatin1String(
"vsi" ) ) )
998 if ( vsiPrefix == QLatin1String(
"vsizip" ) ||
999 vsiPrefix == QLatin1String(
"vsigzip" ) ||
1000 vsiPrefix == QLatin1String(
"vsitar" ) ||
1001 vsiPrefix == QLatin1String(
"vsi7z" ) ||
1002 vsiPrefix == QLatin1String(
"vsirar" ) )
1005 else if ( vsiPrefix == QLatin1String(
"vsicurl" ) ||
1006 vsiPrefix == QLatin1String(
"vsicurl_streaming" ) )
1009 else if ( vsiPrefix == QLatin1String(
"vsis3" ) ||
1010 vsiPrefix == QLatin1String(
"vsicurl_streaming" ) ||
1011 vsiPrefix == QLatin1String(
"vsigs" ) ||
1012 vsiPrefix == QLatin1String(
"vsigs_streaming" ) ||
1013 vsiPrefix == QLatin1String(
"vsiaz" ) ||
1014 vsiPrefix == QLatin1String(
"vsiaz_streaming" ) ||
1015 vsiPrefix == QLatin1String(
"vsiadls" ) ||
1016 vsiPrefix == QLatin1String(
"vsioss" ) ||
1017 vsiPrefix == QLatin1String(
"vsioss_streaming" ) ||
1018 vsiPrefix == QLatin1String(
"vsiswift" ) ||
1019 vsiPrefix == QLatin1String(
"vsiswift_streaming" ) ||
1020 vsiPrefix == QLatin1String(
"vsihdfs" ) ||
1021 vsiPrefix == QLatin1String(
"vsiwebhdfs" ) )
1024 else if ( vsiPrefix == QLatin1String(
"vsimem" ) )
1032 CPLPushErrorHandler( CPLQuietErrorHandler );
1034 GDALDriverH hDriver =
nullptr;
1039 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
1043 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1056 CPLPopErrorHandler();
1057 return static_cast< bool >( hDriver );
1064 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1065 if ( !gdalDriverHelpTopic.isEmpty() )
1066 return QStringLiteral(
"https://gdal.org/%1" ).arg( gdalDriverHelpTopic );
1073 QString vsiPrefix = prefix;
1074 if ( !vsiPrefix.startsWith(
'/' ) )
1075 vsiPrefix.prepend(
'/' );
1076 if ( !vsiPrefix.endsWith(
'/' ) )
1077 vsiPrefix.append(
'/' );
1079 QString vsiPath = path;
1080 if ( vsiPath.endsWith(
'/' ) )
1083 const QString bucket = vsiPrefix + vsiPath;
1085 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1087#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 6, 0)
1088 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1089#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3, 5, 0)
1090 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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
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".