23#define CPL_SUPRESS_CPLUSPLUS
25#include "gdalwarper.h"
26#include "cpl_string.h"
29#include <QNetworkProxy>
37 const QString driverShortName = GDALGetDriverShortName( driver );
38 if ( driverShortName == QLatin1String(
"SQLite" ) )
43 char **driverMetadata = GDALGetMetadata( driver,
nullptr );
44 return CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE,
false ) &&
45 CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false );
55 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
63 const double cellSizeX = extent.
width() / width;
64 const double cellSizeY = extent.
height() / height;
65 double geoTransform[6];
67 geoTransform[1] = cellSizeX;
69 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
71 geoTransform[5] = -cellSizeY;
74 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
80 const double cellSizeX = extent.
width() / width;
81 const double cellSizeY = extent.
height() / height;
82 double geoTransform[6];
84 geoTransform[1] = cellSizeX;
86 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
88 geoTransform[5] = -cellSizeY;
90 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
97 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toLocal8Bit().constData(), width, height, 1, dataType,
nullptr ) );
105 GDALSetGeoTransform( hDstDS.get(), geoTransform );
111 if ( image.isNull() )
114 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( image.constBits() );
115 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
120 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem,
"", image.width(), image.height(), 0, GDT_Byte,
nullptr ) );
123 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
124 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
125 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 2 ) );
126 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
127 CSLDestroy( papszOptions );
130 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
131 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
132 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 1 ) );
133 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
134 CSLDestroy( papszOptions );
137 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
138 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
139 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) ) );
140 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
141 CSLDestroy( papszOptions );
144 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
145 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
146 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 3 ) );
147 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
148 CSLDestroy( papszOptions );
158 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
162 const double cellSizeX = extent.
width() / pixelWidth;
163 const double cellSizeY = extent.
height() / pixelHeight;
164 double geoTransform[6];
165 geoTransform[0] = extent.
xMinimum();
166 geoTransform[1] = cellSizeX;
168 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * pixelHeight );
170 geoTransform[5] = -cellSizeY;
174 int dataTypeSize = GDALGetDataTypeSizeBytes( dataType );
176 << QStringLiteral(
"PIXELOFFSET=%1" ).arg( dataTypeSize )
177 << QStringLiteral(
"LINEOFFSET=%1" ).arg( pixelWidth * dataTypeSize )
178 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( block ) ) );
179 GDALAddBand( hDstDS.get(), dataType, papszOptions );
180 CSLDestroy( papszOptions );
182 GDALSetGeoTransform( hDstDS.get(), geoTransform );
190 psWarpOptions->hSrcDS = hSrcDS;
191 psWarpOptions->hDstDS = hDstDS;
193 psWarpOptions->nBandCount = 1;
194 psWarpOptions->panSrcBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
195 psWarpOptions->panDstBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
196 psWarpOptions->panSrcBands[0] = 1;
197 psWarpOptions->panDstBands[0] = 1;
199 psWarpOptions->eResampleAlg = resampleAlg;
202 char **papszOptions =
nullptr;
203 if ( pszCoordinateOperation !=
nullptr )
204 papszOptions = CSLSetNameValue( papszOptions,
"COORDINATE_OPERATION", pszCoordinateOperation );
205 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
206 CSLDestroy( papszOptions );
208 if ( ! psWarpOptions->pTransformerArg )
213 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
216 GDALWarpOperation oOperation;
217 oOperation.Initialize( psWarpOptions.get() );
219 const bool retVal { oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None };
220 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
230 GDALRasterIOExtraArg extra;
231 INIT_RASTERIO_EXTRA_ARG( extra );
232 extra.eResampleAlg = resampleAlg;
234 QImage res( outputSize, image.format() );
238 GByte *rgb =
reinterpret_cast<GByte *
>( res.bits() );
240 CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
241 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
242 if ( err != CE_None )
244 QgsDebugMsg( QStringLiteral(
"failed to read red band" ) );
248 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
249 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
250 if ( err != CE_None )
252 QgsDebugMsg( QStringLiteral(
"failed to read green band" ) );
256 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
257 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
258 if ( err != CE_None )
260 QgsDebugMsg( QStringLiteral(
"failed to read blue band" ) );
264 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
265 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
266 if ( err != CE_None )
268 QgsDebugMsg( QStringLiteral(
"failed to read alpha band" ) );
278 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
282 char **GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
283 message += QLatin1String(
"Format Details:\n" );
284 message += QStringLiteral(
" Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
285 message += QStringLiteral(
" Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
286 message += QStringLiteral(
" / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
287 message += QStringLiteral(
" Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );
291 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
292 GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
293 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
294 if ( pszFormattedXML )
295 message += QString( pszFormattedXML );
297 CPLDestroyXMLNode( psCOL );
298 if ( pszFormattedXML )
299 CPLFree( pszFormattedXML );
306 char **papszRetList =
nullptr;
307 const auto constList = list;
308 for (
const QString &elem : constList )
310 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
317 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
318 if ( ! myGdalDriver )
319 return QStringLiteral(
"invalid GDAL driver" );
323 const int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
324 CSLDestroy( papszOptions );
327 return QStringLiteral(
"Failed GDALValidateCreationOptions() test" );
333 const char *pszSrcWKT,
334 const char *pszDstWKT,
335 GDALResampleAlg eResampleAlg,
337 const GDALWarpOptions *psOptionsIn )
339 char **opts =
nullptr;
340 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
343 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
345 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
348 return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
353 char **opts = CSLDuplicate( papszOptions );
354 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
357 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
359 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
361 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
366#ifndef QT_NO_NETWORKPROXY
376 if ( settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool() )
380 if ( ! proxies.isEmpty() )
382 const QNetworkProxy proxy( proxies.first() );
387 const QString proxyHost( proxy.hostName() );
388 const quint16 proxyPort( proxy.port() );
390 const QString proxyUser( proxy.user() );
391 const QString proxyPassword( proxy.password() );
393 if ( ! proxyHost.isEmpty() )
395 QString connection( proxyHost );
398 connection +=
':' + QString::number( proxyPort );
400 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
401 if ( ! proxyUser.isEmpty( ) )
403 QString credentials( proxyUser );
404 if ( ! proxyPassword.isEmpty( ) )
406 credentials +=
':' + proxyPassword;
408 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
417 const QFileInfo info( path );
418 const long long size = info.size();
424 const QString suffix = info.suffix().toLower();
425 static const QStringList sFileSizeDependentExtensions
427 QStringLiteral(
"xlsx" ),
428 QStringLiteral(
"ods" ),
429 QStringLiteral(
"csv" )
431 if ( sFileSizeDependentExtensions.contains( suffix ) )
434 return size < smallFileSizeLimit;
444#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
446 static std::once_flag initialized;
447 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
448 std::call_once( initialized, [ = ]
452 GDALDriverH driver =
nullptr;
454 QSet< QString > extensions;
456 for (
int i = 0; i < GDALGetDriverCount(); ++i )
458 driver = GDALGetDriver( i );
465 bool isMultiLayer =
false;
466 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) == QLatin1String(
"YES" ) )
468 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) !=
nullptr )
473 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) == QLatin1String(
"YES" ) )
475 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) !=
nullptr )
484 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
485 if ( driverExtensions.isEmpty() )
488 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
490 for (
const QString &ext : splitExtensions )
491 extensions.insert( ext );
494 SUPPORTED_DB_LAYERS_EXTENSIONS = QStringList( extensions.constBegin(), extensions.constEnd() );
496 return SUPPORTED_DB_LAYERS_EXTENSIONS;
499 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
501 QStringLiteral(
"gpkg" ),
502 QStringLiteral(
"sqlite" ),
503 QStringLiteral(
"db" ),
504 QStringLiteral(
"gdb" ),
505 QStringLiteral(
"kml" ),
506 QStringLiteral(
"kmz" ),
507 QStringLiteral(
"osm" ),
508 QStringLiteral(
"mdb" ),
509 QStringLiteral(
"accdb" ),
510 QStringLiteral(
"xls" ),
511 QStringLiteral(
"xlsx" ),
512 QStringLiteral(
"ods" ),
513 QStringLiteral(
"gpx" ),
514 QStringLiteral(
"pdf" ),
515 QStringLiteral(
"pbf" ),
516 QStringLiteral(
"vrt" ),
517 QStringLiteral(
"nc" ),
518 QStringLiteral(
"shp.zip" ) };
519 return SUPPORTED_DB_LAYERS_EXTENSIONS;
525 CPLPushErrorHandler( CPLQuietErrorHandler );
527 GDALDriverH hDriver =
nullptr;
532 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
536 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
548 CPLPopErrorHandler();
549 return static_cast< bool >( hDriver );
This class represents a coordinate reference system (CRS).
@ WKT_PREFERRED_GDAL
Preferred format for conversion of CRS to WKT for use with the GDAL library.
QString toWkt(WktVariant variant=WKT1_GDAL, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
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 helpCreationOptionsFormat(const QString &format)
Gets creation options metadata for a given format.
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 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 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 an raster block to a single band GDAL memory dataset.
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 bool vrtMatchesLayerType(const QString &vrtPath, QgsMapLayerType type)
Returns true if the VRT file at the specified path is a VRT matching the given layer type.
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 void warning(const QString &msg)
Goes to qWarning.
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
A rectangle specified with double values.
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
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.
QgsMapLayerType
Types of layers that can be added to a map.
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
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.
const QgsCoordinateReferenceSystem & crs