19 #include "qgssettings.h"
21 #define CPL_SUPRESS_CPLUSPLUS
23 #include "gdalwarper.h"
24 #include "cpl_string.h"
26 #include <QNetworkProxy>
32 QString driverShortName = GDALGetDriverShortName( driver );
33 if ( driverShortName == QLatin1String(
"SQLite" ) )
38 char **driverMetadata = GDALGetMetadata( driver,
nullptr );
39 return CSLFetchBoolean( driverMetadata, GDAL_DCAP_CREATE,
false ) &&
40 CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false );
50 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
58 double cellSizeX = extent.
width() / width;
59 double cellSizeY = extent.
height() / height;
60 double geoTransform[6];
62 geoTransform[1] = cellSizeX;
64 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
66 geoTransform[5] = -cellSizeY;
69 GDALSetGeoTransform( hSrcDS.get(), geoTransform );
75 double cellSizeX = extent.
width() / width;
76 double cellSizeY = extent.
height() / height;
77 double geoTransform[6];
79 geoTransform[1] = cellSizeX;
81 geoTransform[3] = extent.
yMinimum() + ( cellSizeY * height );
83 geoTransform[5] = -cellSizeY;
85 GDALDriverH hDriver = GDALGetDriverByName(
"GTiff" );
92 gdal::dataset_unique_ptr hDstDS( GDALCreate( hDriver, filename.toLocal8Bit().constData(), width, height, 1, dataType,
nullptr ) );
100 GDALSetGeoTransform( hDstDS.get(), geoTransform );
106 if ( image.isNull() )
109 const QRgb *rgb =
reinterpret_cast<const QRgb *
>( image.constBits() );
110 GDALDriverH hDriverMem = GDALGetDriverByName(
"MEM" );
115 gdal::dataset_unique_ptr hSrcDS( GDALCreate( hDriverMem,
"", image.width(), image.height(), 0, GDT_Byte,
nullptr ) );
118 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
119 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
120 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 2 ) );
121 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
122 CSLDestroy( papszOptions );
125 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
126 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
127 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 1 ) );
128 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
129 CSLDestroy( papszOptions );
132 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
133 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
134 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) ) );
135 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
136 CSLDestroy( papszOptions );
139 << QStringLiteral(
"PIXELOFFSET=%1" ).arg(
sizeof( QRgb ) )
140 << QStringLiteral(
"LINEOFFSET=%1" ).arg( image.bytesPerLine() )
141 << QStringLiteral(
"DATAPOINTER=%1" ).arg(
reinterpret_cast< qulonglong
>( rgb ) + 3 ) );
142 GDALAddBand( hSrcDS.get(), GDT_Byte, papszOptions );
143 CSLDestroy( papszOptions );
151 psWarpOptions->hSrcDS = hSrcDS;
152 psWarpOptions->hDstDS = hDstDS;
154 psWarpOptions->nBandCount = 1;
155 psWarpOptions->panSrcBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
156 psWarpOptions->panDstBands =
reinterpret_cast< int *
>( CPLMalloc(
sizeof(
int ) * 1 ) );
157 psWarpOptions->panSrcBands[0] = 1;
158 psWarpOptions->panDstBands[0] = 1;
160 psWarpOptions->eResampleAlg = resampleAlg;
163 char **papszOptions =
nullptr;
164 if ( pszCoordinateOperation !=
nullptr )
165 papszOptions = CSLSetNameValue( papszOptions,
"COORDINATE_OPERATION", pszCoordinateOperation );
166 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszOptions );
167 CSLDestroy( papszOptions );
169 if ( ! psWarpOptions->pTransformerArg )
174 psWarpOptions->pfnTransformer = GDALGenImgProjTransform;
177 GDALWarpOperation oOperation;
178 oOperation.Initialize( psWarpOptions.get() );
180 const bool retVal { oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ) == CE_None };
181 GDALDestroyGenImgProjTransformer( psWarpOptions->pTransformerArg );
191 GDALRasterIOExtraArg extra;
192 INIT_RASTERIO_EXTRA_ARG( extra );
193 extra.eResampleAlg = resampleAlg;
195 QImage res( outputSize, image.format() );
199 GByte *rgb =
reinterpret_cast<GByte *
>( res.bits() );
201 CPLErr err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 1 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 2, outputSize.width(),
202 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
203 if ( err != CE_None )
205 QgsDebugMsg( QStringLiteral(
"failed to read red band" ) );
209 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 2 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 1, outputSize.width(),
210 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
211 if ( err != CE_None )
213 QgsDebugMsg( QStringLiteral(
"failed to read green band" ) );
217 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 3 ), GF_Read, 0, 0, image.width(), image.height(), rgb, outputSize.width(),
218 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
219 if ( err != CE_None )
221 QgsDebugMsg( QStringLiteral(
"failed to read blue band" ) );
225 err = GDALRasterIOEx( GDALGetRasterBand( srcDS.get(), 4 ), GF_Read, 0, 0, image.width(), image.height(), rgb + 3, outputSize.width(),
226 outputSize.height(), GDT_Byte,
sizeof( QRgb ), res.bytesPerLine(), &extra );
227 if ( err != CE_None )
229 QgsDebugMsg( QStringLiteral(
"failed to read alpha band" ) );
239 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
243 char **GDALmetadata = GDALGetMetadata( myGdalDriver,
nullptr );
244 message += QLatin1String(
"Format Details:\n" );
245 message += QStringLiteral(
" Extension: %1\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_EXTENSION ) );
246 message += QStringLiteral(
" Short Name: %1" ).arg( GDALGetDriverShortName( myGdalDriver ) );
247 message += QStringLiteral(
" / Long Name: %1\n" ).arg( GDALGetDriverLongName( myGdalDriver ) );
248 message += QStringLiteral(
" Help page: http://www.gdal.org/%1\n\n" ).arg( CSLFetchNameValue( GDALmetadata, GDAL_DMD_HELPTOPIC ) );
252 CPLXMLNode *psCOL = CPLParseXMLString( GDALGetMetadataItem( myGdalDriver,
253 GDAL_DMD_CREATIONOPTIONLIST,
"" ) );
254 char *pszFormattedXML = CPLSerializeXMLTree( psCOL );
255 if ( pszFormattedXML )
256 message += QString( pszFormattedXML );
258 CPLDestroyXMLNode( psCOL );
259 if ( pszFormattedXML )
260 CPLFree( pszFormattedXML );
267 char **papszRetList =
nullptr;
268 const auto constList = list;
269 for (
const QString &elem : constList )
271 papszRetList = CSLAddString( papszRetList, elem.toLocal8Bit().constData() );
278 GDALDriverH myGdalDriver = GDALGetDriverByName( format.toLocal8Bit().constData() );
279 if ( ! myGdalDriver )
280 return QStringLiteral(
"invalid GDAL driver" );
284 int ok = GDALValidateCreationOptions( myGdalDriver, papszOptions );
285 CSLDestroy( papszOptions );
288 return QStringLiteral(
"Failed GDALValidateCreationOptions() test" );
292 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
294 GDALDatasetH GDALAutoCreateWarpedVRTEx(
GDALDatasetH hSrcDS,
const char *pszSrcWKT,
const char *pszDstWKT, GDALResampleAlg eResampleAlg,
295 double dfMaxError,
const GDALWarpOptions *psOptionsIn,
char **papszTransformerOptions )
297 VALIDATE_POINTER1( hSrcDS,
"GDALAutoCreateWarpedVRT",
nullptr );
302 GDALWarpOptions *psWO =
nullptr;
303 if ( psOptionsIn !=
nullptr )
304 psWO = GDALCloneWarpOptions( psOptionsIn );
306 psWO = GDALCreateWarpOptions();
308 psWO->eResampleAlg = eResampleAlg;
310 psWO->hSrcDS = hSrcDS;
312 GDALWarpInitDefaultBandMapping( psWO, GDALGetRasterCount( hSrcDS ) );
317 for (
int i = 0; i < psWO->nBandCount; i++ )
319 GDALRasterBandH rasterBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[i] );
322 double noDataValue = GDALGetRasterNoDataValue( rasterBand, &hasNoDataValue );
324 if ( hasNoDataValue )
327 int bClamped = FALSE;
328 int bRounded = FALSE;
330 GDALAdjustValueToDataType( GDALGetRasterDataType( rasterBand ),
331 noDataValue, &bClamped, &bRounded ) );
334 GDALWarpInitNoDataReal( psWO, -1e10 );
336 psWO->padfSrcNoDataReal[i] = noDataValue;
337 psWO->padfDstNoDataReal[i] = noDataValue;
342 if ( psWO->padfDstNoDataReal !=
nullptr )
344 if ( CSLFetchNameValue( psWO->papszWarpOptions,
"INIT_DEST" ) ==
nullptr )
346 psWO->papszWarpOptions =
347 CSLSetNameValue( psWO->papszWarpOptions,
"INIT_DEST",
"NO_DATA" );
354 psWO->pfnTransformer = GDALGenImgProjTransform;
356 char **papszOptions =
nullptr;
357 if ( pszSrcWKT !=
nullptr )
358 papszOptions = CSLSetNameValue( papszOptions,
"SRC_SRS", pszSrcWKT );
359 if ( pszDstWKT !=
nullptr )
360 papszOptions = CSLSetNameValue( papszOptions,
"DST_SRS", pszDstWKT );
361 papszOptions = CSLMerge( papszOptions, papszTransformerOptions );
362 psWO->pTransformerArg =
363 GDALCreateGenImgProjTransformer2( psWO->hSrcDS,
nullptr,
365 CSLDestroy( papszOptions );
367 if ( psWO->pTransformerArg ==
nullptr )
369 GDALDestroyWarpOptions( psWO );
376 double adfDstGeoTransform[6] = { 0.0 };
380 GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
381 psWO->pTransformerArg,
382 adfDstGeoTransform, &nDstPixels, &nDstLines );
383 if ( eErr != CE_None )
385 GDALDestroyTransformer( psWO->pTransformerArg );
386 GDALDestroyWarpOptions( psWO );
395 GDALSetGenImgProjTransformerDstGeoTransform(
396 psWO->pTransformerArg, adfDstGeoTransform );
401 if ( dfMaxError > 0.0 )
403 psWO->pTransformerArg =
404 GDALCreateApproxTransformer( psWO->pfnTransformer,
405 psWO->pTransformerArg,
407 psWO->pfnTransformer = GDALApproxTransform;
408 GDALApproxTransformerOwnsSubtransformer( psWO->pTransformerArg, TRUE );
415 = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
416 adfDstGeoTransform, psWO );
418 GDALDestroyWarpOptions( psWO );
420 if ( pszDstWKT !=
nullptr )
421 GDALSetProjection( hDstDS, pszDstWKT );
422 else if ( pszSrcWKT !=
nullptr )
423 GDALSetProjection( hDstDS, pszSrcWKT );
424 else if ( GDALGetGCPCount( hSrcDS ) > 0 )
425 GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
427 GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
436 const char *pszSrcWKT,
437 const char *pszDstWKT,
438 GDALResampleAlg eResampleAlg,
440 const GDALWarpOptions *psOptionsIn )
442 char **opts =
nullptr;
443 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
446 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
448 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
451 return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
456 char **opts = CSLDuplicate( papszOptions );
457 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
460 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
462 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
464 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
469 #ifndef QT_NO_NETWORKPROXY
477 QgsSettings settings;
479 if ( settings.value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool() )
483 if ( ! proxies.isEmpty() )
485 QNetworkProxy proxy( proxies.first() );
490 QString proxyHost( proxy.hostName() );
491 qint16 proxyPort( proxy.port() );
493 QString proxyUser( proxy.user() );
494 QString proxyPassword( proxy.password() );
496 if ( ! proxyHost.isEmpty() )
498 QString connection( proxyHost );
501 connection +=
':' + QString::number( proxyPort );
503 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
504 if ( ! proxyUser.isEmpty( ) )
506 QString credentials( proxyUser );
507 if ( ! proxyPassword.isEmpty( ) )
509 credentials +=
':' + proxyPassword;
511 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
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 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 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 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 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.
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