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 )
481 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
485 CSLConstList GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
486 message +=
"<h3>" + QCoreApplication::translate(
"QgsGdalUtils",
"Format Details" ) +
"</h3>";
487 message +=
"<b>" + QCoreApplication::translate(
"QgsGdalUtils",
"Extension:" ) + u
"</b> %1<br>"_s.arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
489 + QCoreApplication::translate(
"QgsGdalUtils",
"Short Name:" )
490 + u
"</b> %1 / <b>"_s.arg( GDALGetDriverShortName( myGdalDriver ) )
491 + QCoreApplication::translate(
"QgsGdalUtils",
"Long Name:" )
492 + u
"</b> %2<br>"_s.arg( GDALGetDriverLongName( myGdalDriver ) );
494 if ( !helpUrl.isEmpty() )
496 message +=
"<b>" + QCoreApplication::translate(
"QgsGdalUtils",
"Help page:" ) + u
"</b> <a href=\"%1\">%1</a>"_s.arg( helpUrl );
501 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver, GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
502 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
503 if ( pszFormattedXML )
506 if ( doc.setContent( QString( pszFormattedXML ) ) )
508 message +=
"<h3>" + QCoreApplication::translate(
"QgsGdalUtils",
"Creation Options" ) +
"</h3>";
510 QDomNodeList options = doc.elementsByTagName( u
"Option"_s );
511 for (
int i = 0; i < options.count(); ++i )
513 QDomElement element = options.at( i ).toElement();
515 const QString optionName = element.attribute( u
"name"_s );
516 const QString optionType = element.attribute( u
"type"_s );
517 const QString optionDefault = element.attribute( u
"default"_s );
518 const QString optionDescription = element.attribute( u
"description"_s );
520 += u
"<dt><b>%1</b> (%2%3)</dt>"_s
521 .arg( optionName.toHtmlEscaped(), optionType.toHtmlEscaped(), optionDefault.isEmpty() ? QString() :
", " + QCoreApplication::translate(
"QgsGdalUtils",
"default: " ) + optionDefault.toHtmlEscaped() );
522 if ( !optionDescription.isEmpty() )
524 message += u
"<dd>%1</dd>"_s.arg( optionDescription.toHtmlEscaped() );
528 QDomNodeList nodes = element.elementsByTagName( u
"Value"_s );
529 if ( !nodes.isEmpty() )
532 for (
int j = 0; j < nodes.count(); ++j )
534 values << nodes.at( j ).toElement().text().toHtmlEscaped();
536 message +=
"<dd><i>" + QCoreApplication::translate(
"QgsGdalUtils",
"Possible values:" ) + u
"</i> %1</dd>"_s.arg( values.join(
", " ) );
544 CPLDestroyXMLNode( psCOL );
545 if ( pszFormattedXML )
546 CPLFree( pszFormattedXML );
554 char **papszRetList =
nullptr;
555 const auto constList = list;
556 for (
const QString &elem : constList )
558 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
565 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
567 return u
"invalid GDAL driver"_s;
571 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
572 CSLDestroy( papszOptions );
575 return u
"Failed GDALValidateCreationOptions() test"_s;
579static void setRPCTransformerOptions(
GDALDatasetH hSrcDS,
char ***opts )
581 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
585 const char *heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_DEFAULT",
"RPC" );
590 heightStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
593 *opts = CSLAddNameValue( *opts,
"RPC_HEIGHT", heightStr );
599 char **opts =
nullptr;
600 setRPCTransformerOptions( hSrcDS, &opts );
601 GDALDatasetH hRetDS = GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
608 char **opts = CSLDuplicate( papszOptions );
609 setRPCTransformerOptions( hSrcDS, &opts );
610 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
620 return GDALDataType::GDT_Unknown;
623 return GDALDataType::GDT_Byte;
626#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
627 return GDALDataType::GDT_Int8;
629 return GDALDataType::GDT_Unknown;
633 return GDALDataType::GDT_UInt16;
636 return GDALDataType::GDT_Int16;
639 return GDALDataType::GDT_UInt32;
642 return GDALDataType::GDT_Int32;
645 return GDALDataType::GDT_Float32;
648 return GDALDataType::GDT_Float64;
651 return GDALDataType::GDT_CInt16;
654 return GDALDataType::GDT_CInt32;
657 return GDALDataType::GDT_CFloat32;
660 return GDALDataType::GDT_CFloat64;
664 return GDALDataType::GDT_Unknown;
668 return GDALDataType::GDT_Unknown;
673 GDALResampleAlg eResampleAlg = GRA_NearestNeighbour;
678 eResampleAlg = GRA_NearestNeighbour;
682 eResampleAlg = GRA_Bilinear;
686 eResampleAlg = GRA_Cubic;
690 eResampleAlg = GRA_CubicSpline;
694 eResampleAlg = GRA_Lanczos;
698 eResampleAlg = GRA_Average;
702 eResampleAlg = GRA_Mode;
709#ifndef QT_NO_NETWORKPROXY
722 if ( !proxies.isEmpty() )
724 const QNetworkProxy proxy( proxies.first() );
727 const QString proxyHost( proxy.hostName() );
728 const quint16 proxyPort( proxy.port() );
730 const QString proxyUser( proxy.user() );
731 const QString proxyPassword( proxy.password() );
733 if ( !proxyHost.isEmpty() )
735 QString connection( proxyHost );
738 connection +=
':' + QString::number( proxyPort );
740 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
741 if ( !proxyUser.isEmpty() )
743 QString credentials( proxyUser );
744 if ( !proxyPassword.isEmpty() )
746 credentials +=
':' + proxyPassword;
748 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
757 const QFileInfo info( path );
758 const long long size = info.size();
764 const QString suffix = info.suffix().toLower();
765 static const QStringList sFileSizeDependentExtensions { u
"xlsx"_s, u
"ods"_s, u
"csv"_s };
766 if ( sFileSizeDependentExtensions.contains( suffix ) )
769 return size < smallFileSizeLimit;
779#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 4, 0 )
781 static std::once_flag initialized;
782 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
783 std::call_once( initialized, [] {
786 GDALDriverH driver =
nullptr;
788 QSet< QString > extensions;
790 for (
int i = 0; i < GDALGetDriverCount(); ++i )
792 driver = GDALGetDriver( i );
799 bool isMultiLayer =
false;
800 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) ==
"YES"_L1 )
802 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) )
807 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) ==
"YES"_L1 )
809 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) )
818 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
819 if ( driverExtensions.isEmpty() )
822 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
824 for (
const QString &ext : splitExtensions )
827 if ( ext ==
"tif"_L1 || ext ==
"tiff"_L1 )
830 extensions.insert( ext );
834 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
836 return SUPPORTED_DB_LAYERS_EXTENSIONS;
839 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,
840 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 };
841 return SUPPORTED_DB_LAYERS_EXTENSIONS;
849 const thread_local QRegularExpression vsiRx( u
"^(/vsi.+?/)"_s, QRegularExpression::PatternOption::CaseInsensitiveOption );
850 const QRegularExpressionMatch vsiMatch = vsiRx.match( path );
851 if ( vsiMatch.hasMatch() )
852 return vsiMatch.captured( 1 );
854 if ( path.endsWith(
".shp.zip"_L1, Qt::CaseInsensitive ) || path.endsWith(
".gdb.zip"_L1, Qt::CaseInsensitive ) )
857 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr ) )
859 return u
"/vsizip/"_s;
861 else if ( path.endsWith(
".zip"_L1, Qt::CaseInsensitive ) )
864 const char *
const apszAllowedDrivers[] = {
"GTFS",
nullptr };
865 if ( GDALIdentifyDriverEx( path.toUtf8().constData(), GDAL_OF_VECTOR, apszAllowedDrivers,
nullptr ) )
867 return u
"/vsizip/"_s;
869 else if ( path.endsWith(
".tar"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tar.gz"_L1, Qt::CaseInsensitive ) || path.endsWith(
".tgz"_L1, Qt::CaseInsensitive ) )
870 return u
"/vsitar/"_s;
871 else if ( path.endsWith(
".gz"_L1, Qt::CaseInsensitive ) )
872 return u
"/vsigzip/"_s;
873#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
874 else if ( vsiPrefixes.contains( u
"/vsi7z/"_s ) &&
875 ( path.endsWith(
".7z"_L1, Qt::CaseInsensitive ) ||
876 path.endsWith(
".lpk"_L1, Qt::CaseInsensitive ) ||
877 path.endsWith(
".lpkx"_L1, Qt::CaseInsensitive ) ||
878 path.endsWith(
".mpk"_L1, Qt::CaseInsensitive ) ||
879 path.endsWith(
".mpkx"_L1, Qt::CaseInsensitive ) ) )
881 else if ( vsiPrefixes.contains( u
"/vsirar/"_s ) && path.endsWith(
".rar"_L1, Qt::CaseInsensitive ) )
882 return u
"/vsirar/"_s;
895#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
896 res.append( u
"/vsi7z/"_s );
897 res.append( u
"/vsirar/"_s );
905 static std::once_flag initialized;
906 static QList<QgsGdalUtils::VsiNetworkFileSystemDetails> VSI_FILE_SYSTEM_DETAILS;
907 std::call_once( initialized, [] {
908 if (
char **papszPrefixes = VSIGetFileSystemsPrefixes() )
910 for (
int i = 0; papszPrefixes[i]; i++ )
913 details.
identifier = QString( papszPrefixes[i] );
920 details.
name = QObject::tr(
"HTTP/HTTPS/FTP" );
922 details.
name = QObject::tr(
"AWS S3" );
924 details.
name = QObject::tr(
"Google Cloud Storage" );
926 details.
name = QObject::tr(
"Microsoft Azure Blob" );
927 else if ( details.
identifier ==
"vsiadls"_L1 )
928 details.
name = QObject::tr(
"Microsoft Azure Data Lake Storage" );
930 details.
name = QObject::tr(
"Alibaba Cloud OSS" );
931 else if ( details.
identifier ==
"vsiswift"_L1 )
932 details.
name = QObject::tr(
"OpenStack Swift Object Storage" );
933 else if ( details.
identifier ==
"vsihdfs"_L1 )
934 details.
name = QObject::tr(
"Hadoop File System" );
937 VSI_FILE_SYSTEM_DETAILS.append( details );
940 CSLDestroy( papszPrefixes );
944 return VSI_FILE_SYSTEM_DETAILS;
950 for (
const QString &archivePrefix : prefixes )
953 if ( prefix.contains( archivePrefix ) )
968#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 7, 0 )
969 res.append( { u
".7z"_s, u
".lpk"_s, u
".lpkx"_s, u
".mpk"_s, u
".mpkx"_s, u
".rar"_s } );
976 const QString extWithDot = extension.startsWith(
'.' ) ? extension : (
'.' + extension );
982 if ( prefix.isEmpty() )
985 QString vsiPrefix = prefix;
986 if ( vsiPrefix.startsWith(
'/' ) )
987 vsiPrefix = vsiPrefix.mid( 1 );
988 if ( vsiPrefix.endsWith(
'/' ) )
991 if ( !vsiPrefix.startsWith(
"vsi"_L1 ) )
994 if ( vsiPrefix ==
"vsizip"_L1 || vsiPrefix ==
"vsigzip"_L1 || vsiPrefix ==
"vsitar"_L1 || vsiPrefix ==
"vsi7z"_L1 || vsiPrefix ==
"vsirar"_L1 )
997 else if ( vsiPrefix ==
"vsicurl"_L1 || vsiPrefix ==
"vsicurl_streaming"_L1 )
1000 else if ( vsiPrefix ==
"vsis3"_L1
1001 || vsiPrefix ==
"vsicurl_streaming"_L1
1002 || vsiPrefix ==
"vsigs"_L1
1003 || vsiPrefix ==
"vsigs_streaming"_L1
1004 || vsiPrefix ==
"vsiaz"_L1
1005 || vsiPrefix ==
"vsiaz_streaming"_L1
1006 || vsiPrefix ==
"vsiadls"_L1
1007 || vsiPrefix ==
"vsioss"_L1
1008 || vsiPrefix ==
"vsioss_streaming"_L1
1009 || vsiPrefix ==
"vsiswift"_L1
1010 || vsiPrefix ==
"vsiswift_streaming"_L1
1011 || vsiPrefix ==
"vsihdfs"_L1
1012 || vsiPrefix ==
"vsiwebhdfs"_L1 )
1015 else if ( vsiPrefix ==
"vsimem"_L1 )
1023 CPLPushErrorHandler( CPLQuietErrorHandler );
1025 GDALDriverH hDriver =
nullptr;
1030 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
1034 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
1047 CPLPopErrorHandler();
1048 return static_cast< bool >( hDriver );
1055 const QString gdalDriverHelpTopic = GDALGetMetadataItem( hDriver, GDAL_DMD_HELPTOPIC,
nullptr );
1056 if ( !gdalDriverHelpTopic.isEmpty() )
1057 return u
"https://gdal.org/%1"_s.arg( gdalDriverHelpTopic );
1064 GDALDriverH hDriver = GDALGetDriverByName(
"MRF" );
1067 const char *creationOptions = GDALGetMetadataItem( hDriver, GDAL_DMD_CREATIONOPTIONLIST, NULL );
1068 if ( creationOptions && strstr( creationOptions,
"LERC" ) )
1078 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
1081 const char *creationOptions = GDALGetMetadataItem( hDriver, GDAL_DMD_CREATIONOPTIONLIST, NULL );
1082 if ( creationOptions && strstr( creationOptions,
"LERC" ) )
1092 QString vsiPrefix = prefix;
1093 if ( !vsiPrefix.startsWith(
'/' ) )
1094 vsiPrefix.prepend(
'/' );
1095 if ( !vsiPrefix.endsWith(
'/' ) )
1096 vsiPrefix.append(
'/' );
1098 QString vsiPath = path;
1099 if ( vsiPath.endsWith(
'/' ) )
1102 const QString bucket = vsiPrefix + vsiPath;
1104 for (
auto it = options.constBegin(); it != options.constEnd(); ++it )
1106#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 6, 0 )
1107 VSISetPathSpecificOption( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1108#elif GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION( 3, 5, 0 )
1109 VSISetCredential( bucket.toUtf8().constData(), it.key().toUtf8().constData(), it.value().toString().toUtf8().constData() );
1121 : mFeedback( feedback )
1122 , mStartPercentage( startPercentage )
1123 , mEndPercentage( endPercentage )
1133 feedback->setProgress( adapter->mStartPercentage + ( adapter->mEndPercentage - adapter->mStartPercentage ) * dfComplete );
1135 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".