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