23 #define CPL_SUPRESS_CPLUSPLUS //#spellok
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" );
331 #if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,2,0)
333 GDALDatasetH GDALAutoCreateWarpedVRTEx(
GDALDatasetH hSrcDS,
const char *pszSrcWKT,
const char *pszDstWKT, GDALResampleAlg eResampleAlg,
334 double dfMaxError,
const GDALWarpOptions *psOptionsIn,
char **papszTransformerOptions )
336 VALIDATE_POINTER1( hSrcDS,
"GDALAutoCreateWarpedVRT",
nullptr );
341 GDALWarpOptions *psWO =
nullptr;
342 if ( psOptionsIn !=
nullptr )
343 psWO = GDALCloneWarpOptions( psOptionsIn );
345 psWO = GDALCreateWarpOptions();
347 psWO->eResampleAlg = eResampleAlg;
349 psWO->hSrcDS = hSrcDS;
351 GDALWarpInitDefaultBandMapping( psWO, GDALGetRasterCount( hSrcDS ) );
356 for (
int i = 0; i < psWO->nBandCount; i++ )
358 GDALRasterBandH rasterBand = GDALGetRasterBand( psWO->hSrcDS, psWO->panSrcBands[i] );
361 double noDataValue = GDALGetRasterNoDataValue( rasterBand, &hasNoDataValue );
363 if ( hasNoDataValue )
366 int bClamped = FALSE;
367 int bRounded = FALSE;
369 GDALAdjustValueToDataType( GDALGetRasterDataType( rasterBand ),
370 noDataValue, &bClamped, &bRounded ) );
373 GDALWarpInitNoDataReal( psWO, -1e10 );
375 psWO->padfSrcNoDataReal[i] = noDataValue;
376 psWO->padfDstNoDataReal[i] = noDataValue;
381 if ( psWO->padfDstNoDataReal !=
nullptr )
383 if ( CSLFetchNameValue( psWO->papszWarpOptions,
"INIT_DEST" ) ==
nullptr )
385 psWO->papszWarpOptions =
386 CSLSetNameValue( psWO->papszWarpOptions,
"INIT_DEST",
"NO_DATA" );
393 psWO->pfnTransformer = GDALGenImgProjTransform;
395 char **papszOptions =
nullptr;
396 if ( pszSrcWKT !=
nullptr )
397 papszOptions = CSLSetNameValue( papszOptions,
"SRC_SRS", pszSrcWKT );
398 if ( pszDstWKT !=
nullptr )
399 papszOptions = CSLSetNameValue( papszOptions,
"DST_SRS", pszDstWKT );
400 papszOptions = CSLMerge( papszOptions, papszTransformerOptions );
401 psWO->pTransformerArg =
402 GDALCreateGenImgProjTransformer2( psWO->hSrcDS,
nullptr,
404 CSLDestroy( papszOptions );
406 if ( psWO->pTransformerArg ==
nullptr )
408 GDALDestroyWarpOptions( psWO );
415 double adfDstGeoTransform[6] = { 0.0 };
419 GDALSuggestedWarpOutput( hSrcDS, psWO->pfnTransformer,
420 psWO->pTransformerArg,
421 adfDstGeoTransform, &nDstPixels, &nDstLines );
422 if ( eErr != CE_None )
424 GDALDestroyTransformer( psWO->pTransformerArg );
425 GDALDestroyWarpOptions( psWO );
434 GDALSetGenImgProjTransformerDstGeoTransform(
435 psWO->pTransformerArg, adfDstGeoTransform );
440 if ( dfMaxError > 0.0 )
442 psWO->pTransformerArg =
443 GDALCreateApproxTransformer( psWO->pfnTransformer,
444 psWO->pTransformerArg,
446 psWO->pfnTransformer = GDALApproxTransform;
447 GDALApproxTransformerOwnsSubtransformer( psWO->pTransformerArg, TRUE );
454 = GDALCreateWarpedVRT( hSrcDS, nDstPixels, nDstLines,
455 adfDstGeoTransform, psWO );
457 GDALDestroyWarpOptions( psWO );
459 if ( pszDstWKT !=
nullptr )
460 GDALSetProjection( hDstDS, pszDstWKT );
461 else if ( pszSrcWKT !=
nullptr )
462 GDALSetProjection( hDstDS, pszSrcWKT );
463 else if ( GDALGetGCPCount( hSrcDS ) > 0 )
464 GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
466 GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
475 const char *pszSrcWKT,
476 const char *pszDstWKT,
477 GDALResampleAlg eResampleAlg,
479 const GDALWarpOptions *psOptionsIn )
481 char **opts =
nullptr;
482 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
485 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
487 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
490 return GDALAutoCreateWarpedVRTEx( hSrcDS, pszSrcWKT, pszDstWKT, eResampleAlg, dfMaxError, psOptionsIn, opts );
495 char **opts = CSLDuplicate( papszOptions );
496 if ( GDALGetMetadata( hSrcDS,
"RPC" ) )
499 const char *heightOffStr = GDALGetMetadataItem( hSrcDS,
"HEIGHT_OFF",
"RPC" );
501 opts = CSLAddNameValue( opts,
"RPC_HEIGHT", heightOffStr );
503 void *transformer = GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, opts );
508 #ifndef QT_NO_NETWORKPROXY
518 if ( settings.
value( QStringLiteral(
"proxy/proxyEnabled" ),
false ).toBool() )
522 if ( ! proxies.isEmpty() )
524 const QNetworkProxy proxy( proxies.first() );
529 const QString proxyHost( proxy.hostName() );
530 const quint16 proxyPort( proxy.port() );
532 const QString proxyUser( proxy.user() );
533 const QString proxyPassword( proxy.password() );
535 if ( ! proxyHost.isEmpty() )
537 QString connection( proxyHost );
540 connection +=
':' + QString::number( proxyPort );
542 CPLSetConfigOption(
"GDAL_HTTP_PROXY", connection.toUtf8() );
543 if ( ! proxyUser.isEmpty( ) )
545 QString credentials( proxyUser );
546 if ( ! proxyPassword.isEmpty( ) )
548 credentials +=
':' + proxyPassword;
550 CPLSetConfigOption(
"GDAL_HTTP_PROXYUSERPWD", credentials.toUtf8() );
559 const QFileInfo info( path );
560 const long long size = info.size();
566 const QString suffix = info.suffix().toLower();
567 static const QStringList sFileSizeDependentExtensions
569 QStringLiteral(
"xlsx" ),
570 QStringLiteral(
"ods" ),
571 QStringLiteral(
"csv" )
573 if ( sFileSizeDependentExtensions.contains( suffix ) )
576 return size < smallFileSizeLimit;
586 #if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(3,4,0)
588 static std::once_flag initialized;
589 static QStringList SUPPORTED_DB_LAYERS_EXTENSIONS;
590 std::call_once( initialized, [ = ]
594 GDALDriverH driver =
nullptr;
596 QSet< QString > extensions;
598 for (
int i = 0; i < GDALGetDriverCount(); ++i )
600 driver = GDALGetDriver( i );
607 bool isMultiLayer =
false;
608 if ( QString( GDALGetMetadataItem( driver, GDAL_DCAP_RASTER,
nullptr ) ) == QLatin1String(
"YES" ) )
610 if ( GDALGetMetadataItem( driver, GDAL_DMD_SUBDATASETS,
nullptr ) !=
nullptr )
615 if ( !isMultiLayer && QString( GDALGetMetadataItem( driver, GDAL_DCAP_VECTOR,
nullptr ) ) == QLatin1String(
"YES" ) )
617 if ( GDALGetMetadataItem( driver, GDAL_DCAP_MULTIPLE_VECTOR_LAYERS,
nullptr ) !=
nullptr )
626 const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS,
"" );
627 if ( driverExtensions.isEmpty() )
630 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
631 const QStringList splitExtensions = driverExtensions.split(
' ', QString::SkipEmptyParts );
633 const QStringList splitExtensions = driverExtensions.split(
' ', Qt::SkipEmptyParts );
636 for (
const QString &ext : splitExtensions )
637 extensions.insert( ext );
640 SUPPORTED_DB_LAYERS_EXTENSIONS = qgis::setToList( extensions );
642 return SUPPORTED_DB_LAYERS_EXTENSIONS;
645 static const QStringList SUPPORTED_DB_LAYERS_EXTENSIONS
647 QStringLiteral(
"gpkg" ),
648 QStringLiteral(
"sqlite" ),
649 QStringLiteral(
"db" ),
650 QStringLiteral(
"gdb" ),
651 QStringLiteral(
"kml" ),
652 QStringLiteral(
"kmz" ),
653 QStringLiteral(
"osm" ),
654 QStringLiteral(
"mdb" ),
655 QStringLiteral(
"accdb" ),
656 QStringLiteral(
"xls" ),
657 QStringLiteral(
"xlsx" ),
658 QStringLiteral(
"ods" ),
659 QStringLiteral(
"gpx" ),
660 QStringLiteral(
"pdf" ),
661 QStringLiteral(
"pbf" ),
662 QStringLiteral(
"vrt" ),
663 QStringLiteral(
"nc" ),
664 QStringLiteral(
"shp.zip" ) };
665 return SUPPORTED_DB_LAYERS_EXTENSIONS;
671 CPLPushErrorHandler( CPLQuietErrorHandler );
673 GDALDriverH hDriver =
nullptr;
678 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_VECTOR,
nullptr,
nullptr );
682 hDriver = GDALIdentifyDriverEx( vrtPath.toUtf8().constData(), GDAL_OF_RASTER,
nullptr,
nullptr );
694 CPLPopErrorHandler();
695 return static_cast< bool >( hDriver );