LCOV - code coverage report
Current view: top level - core/providers/gdal - qgsgdalproviderbase.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 3 221 1.4 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :   qgsgdalproviderbase.cpp  - Common base class for GDAL and WCS provider
       3                 :            :                              -------------------
       4                 :            :     begin                : November, 2010
       5                 :            :     copyright            : (C) 2010 by Radim Blazek
       6                 :            :     email                : radim dot blazek at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #include "qgsgdalproviderbase.h"
      19                 :            : ///@cond PRIVATE
      20                 :            : 
      21                 :            : #define CPL_SUPRESS_CPLUSPLUS  //#spellok
      22                 :            : #include <cpl_conv.h>
      23                 :            : #include <cpl_string.h>
      24                 :            : 
      25                 :            : #include "qgsapplication.h"
      26                 :            : #include "qgslogger.h"
      27                 :            : #include "qgsgdalproviderbase.h"
      28                 :            : #include "qgssettings.h"
      29                 :            : 
      30                 :            : #include <mutex>
      31                 :            : #include <QRegularExpression>
      32                 :            : #include <QRegularExpressionMatch>
      33                 :            : 
      34                 :          0 : QgsGdalProviderBase::QgsGdalProviderBase()
      35                 :            : {
      36                 :            : 
      37                 :            :   // first get the GDAL driver manager
      38                 :          0 :   QgsGdalProviderBase::registerGdalDrivers();
      39                 :          0 : }
      40                 :            : 
      41                 :            : /**
      42                 :            :  * \param bandNumber the number of the band for which you want a color table
      43                 :            :  * \param list a pointer the object that will hold the color table
      44                 :            :  * \return TRUE of a color table was able to be read, FALSE otherwise
      45                 :            :  */
      46                 :          0 : QList<QgsColorRampShader::ColorRampItem> QgsGdalProviderBase::colorTable( GDALDatasetH gdalDataset, int bandNumber )const
      47                 :            : {
      48                 :          0 :   QList<QgsColorRampShader::ColorRampItem> ct;
      49                 :            : 
      50                 :            :   //Invalid band number, segfault prevention
      51                 :          0 :   if ( 0 >= bandNumber )
      52                 :            :   {
      53                 :          0 :     QgsDebugMsg( QStringLiteral( "Invalid parameter" ) );
      54                 :          0 :     return ct;
      55                 :            :   }
      56                 :            : 
      57                 :          0 :   GDALRasterBandH myGdalBand = GDALGetRasterBand( gdalDataset, bandNumber );
      58                 :          0 :   GDALColorTableH myGdalColorTable = GDALGetRasterColorTable( myGdalBand );
      59                 :            : 
      60                 :          0 :   if ( myGdalColorTable )
      61                 :            :   {
      62                 :          0 :     QgsDebugMsgLevel( QStringLiteral( "Color table found" ), 2 );
      63                 :            : 
      64                 :            :     // load category labels
      65                 :          0 :     char **categoryNames = GDALGetRasterCategoryNames( myGdalBand );
      66                 :          0 :     QVector<QString> labels;
      67                 :          0 :     if ( categoryNames )
      68                 :            :     {
      69                 :          0 :       int i = 0;
      70                 :          0 :       while ( categoryNames[i] )
      71                 :            :       {
      72                 :          0 :         labels.append( QString( categoryNames[i] ) );
      73                 :          0 :         i++;
      74                 :            :       }
      75                 :          0 :     }
      76                 :            : 
      77                 :          0 :     int myEntryCount = GDALGetColorEntryCount( myGdalColorTable );
      78                 :          0 :     GDALColorInterp myColorInterpretation = GDALGetRasterColorInterpretation( myGdalBand );
      79                 :          0 :     QgsDebugMsgLevel( "Color Interpretation: " + QString::number( static_cast< int >( myColorInterpretation ) ), 2 );
      80                 :          0 :     GDALPaletteInterp myPaletteInterpretation  = GDALGetPaletteInterpretation( myGdalColorTable );
      81                 :          0 :     QgsDebugMsgLevel( "Palette Interpretation: " + QString::number( static_cast< int >( myPaletteInterpretation ) ), 2 );
      82                 :            : 
      83                 :          0 :     const GDALColorEntry *myColorEntry = nullptr;
      84                 :          0 :     for ( int myIterator = 0; myIterator < myEntryCount; myIterator++ )
      85                 :            :     {
      86                 :          0 :       myColorEntry = GDALGetColorEntry( myGdalColorTable, myIterator );
      87                 :            : 
      88                 :          0 :       if ( !myColorEntry )
      89                 :            :       {
      90                 :          0 :         continue;
      91                 :            :       }
      92                 :            :       else
      93                 :            :       {
      94                 :          0 :         QString label = labels.value( myIterator );
      95                 :          0 :         if ( label.isEmpty() )
      96                 :            :         {
      97                 :          0 :           label = QString::number( myIterator );
      98                 :          0 :         }
      99                 :            :         //Branch on the color interpretation type
     100                 :          0 :         if ( myColorInterpretation == GCI_GrayIndex )
     101                 :            :         {
     102                 :          0 :           QgsColorRampShader::ColorRampItem myColorRampItem;
     103                 :          0 :           myColorRampItem.value = static_cast< double >( myIterator );
     104                 :          0 :           myColorRampItem.label = label;
     105                 :          0 :           myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 );
     106                 :          0 :           ct.append( myColorRampItem );
     107                 :          0 :         }
     108                 :          0 :         else if ( myColorInterpretation == GCI_PaletteIndex )
     109                 :            :         {
     110                 :          0 :           QgsColorRampShader::ColorRampItem myColorRampItem;
     111                 :          0 :           myColorRampItem.value = static_cast< double >( myIterator );
     112                 :          0 :           myColorRampItem.label = label;
     113                 :            :           //Branch on palette interpretation
     114                 :          0 :           if ( myPaletteInterpretation  == GPI_RGB )
     115                 :            :           {
     116                 :          0 :             myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
     117                 :          0 :           }
     118                 :          0 :           else if ( myPaletteInterpretation  == GPI_CMYK )
     119                 :            :           {
     120                 :          0 :             myColorRampItem.color = QColor::fromCmyk( myColorEntry->c1, myColorEntry->c2, myColorEntry->c3, myColorEntry->c4 );
     121                 :          0 :           }
     122                 :          0 :           else if ( myPaletteInterpretation  == GPI_HLS )
     123                 :            :           {
     124                 :          0 :             myColorRampItem.color = QColor::fromHsv( myColorEntry->c1, myColorEntry->c3, myColorEntry->c2, myColorEntry->c4 );
     125                 :          0 :           }
     126                 :            :           else
     127                 :            :           {
     128                 :          0 :             myColorRampItem.color = QColor::fromRgb( myColorEntry->c1, myColorEntry->c1, myColorEntry->c1, myColorEntry->c4 );
     129                 :            :           }
     130                 :          0 :           ct.append( myColorRampItem );
     131                 :          0 :         }
     132                 :            :         else
     133                 :            :         {
     134                 :          0 :           QgsDebugMsgLevel( QStringLiteral( "Color interpretation type not supported yet" ), 2 );
     135                 :          0 :           return ct;
     136                 :            :         }
     137                 :          0 :       }
     138                 :          0 :     }
     139                 :          0 :   }
     140                 :            :   else
     141                 :            :   {
     142                 :          0 :     QgsDebugMsgLevel( "No color table found for band " + QString::number( bandNumber ), 2 );
     143                 :          0 :     return ct;
     144                 :            :   }
     145                 :            : 
     146                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Color table loaded successfully" ), 2 );
     147                 :          0 :   return ct;
     148                 :          0 : }
     149                 :            : 
     150                 :          0 : Qgis::DataType QgsGdalProviderBase::dataTypeFromGdal( const GDALDataType gdalDataType ) const
     151                 :            : {
     152                 :          0 :   switch ( gdalDataType )
     153                 :            :   {
     154                 :            :     case GDT_Byte:
     155                 :          0 :       return Qgis::Byte;
     156                 :            :     case GDT_UInt16:
     157                 :          0 :       return Qgis::UInt16;
     158                 :            :     case GDT_Int16:
     159                 :          0 :       return Qgis::Int16;
     160                 :            :     case GDT_UInt32:
     161                 :          0 :       return Qgis::UInt32;
     162                 :            :     case GDT_Int32:
     163                 :          0 :       return Qgis::Int32;
     164                 :            :     case GDT_Float32:
     165                 :          0 :       return Qgis::Float32;
     166                 :            :     case GDT_Float64:
     167                 :          0 :       return Qgis::Float64;
     168                 :            :     case GDT_CInt16:
     169                 :          0 :       return Qgis::CInt16;
     170                 :            :     case GDT_CInt32:
     171                 :          0 :       return Qgis::CInt32;
     172                 :            :     case GDT_CFloat32:
     173                 :          0 :       return Qgis::CFloat32;
     174                 :            :     case GDT_CFloat64:
     175                 :          0 :       return Qgis::CFloat64;
     176                 :            :     case GDT_Unknown:
     177                 :            :     case GDT_TypeCount:
     178                 :          0 :       return Qgis::UnknownDataType;
     179                 :            :   }
     180                 :          0 :   return Qgis::UnknownDataType;
     181                 :          0 : }
     182                 :            : 
     183                 :          0 : int QgsGdalProviderBase::colorInterpretationFromGdal( const GDALColorInterp gdalColorInterpretation ) const
     184                 :            : {
     185                 :          0 :   switch ( gdalColorInterpretation )
     186                 :            :   {
     187                 :            :     case GCI_GrayIndex:
     188                 :          0 :       return QgsRaster::GrayIndex;
     189                 :            :     case GCI_PaletteIndex:
     190                 :          0 :       return QgsRaster::PaletteIndex;
     191                 :            :     case GCI_RedBand:
     192                 :          0 :       return QgsRaster::RedBand;
     193                 :            :     case GCI_GreenBand:
     194                 :          0 :       return QgsRaster::GreenBand;
     195                 :            :     case GCI_BlueBand:
     196                 :          0 :       return QgsRaster::BlueBand;
     197                 :            :     case GCI_AlphaBand:
     198                 :          0 :       return QgsRaster::AlphaBand;
     199                 :            :     case GCI_HueBand:
     200                 :          0 :       return QgsRaster::HueBand;
     201                 :            :     case GCI_SaturationBand:
     202                 :          0 :       return QgsRaster::SaturationBand;
     203                 :            :     case GCI_LightnessBand:
     204                 :          0 :       return QgsRaster::LightnessBand;
     205                 :            :     case GCI_CyanBand:
     206                 :          0 :       return QgsRaster::CyanBand;
     207                 :            :     case GCI_MagentaBand:
     208                 :          0 :       return QgsRaster::MagentaBand;
     209                 :            :     case GCI_YellowBand:
     210                 :          0 :       return QgsRaster::YellowBand;
     211                 :            :     case GCI_BlackBand:
     212                 :          0 :       return QgsRaster::BlackBand;
     213                 :            :     case GCI_YCbCr_YBand:
     214                 :          0 :       return QgsRaster::YCbCr_YBand;
     215                 :            :     case GCI_YCbCr_CbBand:
     216                 :          0 :       return QgsRaster::YCbCr_CbBand;
     217                 :            :     case GCI_YCbCr_CrBand:
     218                 :          0 :       return QgsRaster::YCbCr_CrBand;
     219                 :            :     case GCI_Undefined:
     220                 :          0 :       return QgsRaster::UndefinedColorInterpretation;
     221                 :            :   }
     222                 :          0 :   return QgsRaster::UndefinedColorInterpretation;
     223                 :          0 : }
     224                 :            : 
     225                 :          3 : void QgsGdalProviderBase::registerGdalDrivers()
     226                 :            : {
     227                 :            :   static std::once_flag initialized;
     228                 :          3 :   std::call_once( initialized, QgsApplication::registerGdalDriversFromSettings );
     229                 :          3 : }
     230                 :            : 
     231                 :          0 : QgsRectangle QgsGdalProviderBase::extent( GDALDatasetH gdalDataset )const
     232                 :            : {
     233                 :            :   double myGeoTransform[6];
     234                 :            : 
     235                 :          0 :   bool myHasGeoTransform = GDALGetGeoTransform( gdalDataset, myGeoTransform ) == CE_None;
     236                 :          0 :   if ( !myHasGeoTransform )
     237                 :            :   {
     238                 :            :     // Initialize the affine transform matrix
     239                 :          0 :     myGeoTransform[0] = 0;
     240                 :          0 :     myGeoTransform[1] = 1;
     241                 :          0 :     myGeoTransform[2] = 0;
     242                 :          0 :     myGeoTransform[3] = 0;
     243                 :          0 :     myGeoTransform[4] = 0;
     244                 :          0 :     myGeoTransform[5] = -1;
     245                 :          0 :   }
     246                 :            : 
     247                 :            :   // Use the affine transform to get geo coordinates for
     248                 :            :   // the corners of the raster
     249                 :          0 :   double myXMax = myGeoTransform[0] +
     250                 :          0 :                   GDALGetRasterXSize( gdalDataset ) * myGeoTransform[1] +
     251                 :          0 :                   GDALGetRasterYSize( gdalDataset ) * myGeoTransform[2];
     252                 :          0 :   double myYMin = myGeoTransform[3] +
     253                 :          0 :                   GDALGetRasterXSize( gdalDataset ) * myGeoTransform[4] +
     254                 :          0 :                   GDALGetRasterYSize( gdalDataset ) * myGeoTransform[5];
     255                 :            : 
     256                 :          0 :   QgsRectangle extent( myGeoTransform[0], myYMin, myXMax, myGeoTransform[3] );
     257                 :          0 :   return extent;
     258                 :            : }
     259                 :            : 
     260                 :          0 : GDALDatasetH QgsGdalProviderBase::gdalOpen( const QString &uri, unsigned int nOpenFlags )
     261                 :            : {
     262                 :          0 :   QVariantMap parts = decodeGdalUri( uri );
     263                 :          0 :   const QStringList openOptions = parts.value( QStringLiteral( "openOptions" ) ).toStringList();
     264                 :          0 :   parts.remove( QStringLiteral( "openOptions" ) );
     265                 :            : 
     266                 :          0 :   char **papszOpenOptions = nullptr;
     267                 :          0 :   for ( const QString &option : openOptions )
     268                 :            :   {
     269                 :          0 :     papszOpenOptions = CSLAddString( papszOpenOptions,
     270                 :          0 :                                      option.toUtf8().constData() );
     271                 :            :   }
     272                 :            : 
     273                 :          0 :   bool modify_OGR_GPKG_FOREIGN_KEY_CHECK = !CPLGetConfigOption( "OGR_GPKG_FOREIGN_KEY_CHECK", nullptr );
     274                 :          0 :   if ( modify_OGR_GPKG_FOREIGN_KEY_CHECK )
     275                 :            :   {
     276                 :          0 :     CPLSetThreadLocalConfigOption( "OGR_GPKG_FOREIGN_KEY_CHECK", "NO" );
     277                 :          0 :   }
     278                 :            : 
     279                 :          0 :   GDALDatasetH hDS = GDALOpenEx( encodeGdalUri( parts ).toUtf8().constData(), nOpenFlags, nullptr, papszOpenOptions, nullptr );
     280                 :          0 :   CSLDestroy( papszOpenOptions );
     281                 :            : 
     282                 :          0 :   if ( modify_OGR_GPKG_FOREIGN_KEY_CHECK )
     283                 :            :   {
     284                 :          0 :     CPLSetThreadLocalConfigOption( "OGR_GPKG_FOREIGN_KEY_CHECK", nullptr );
     285                 :          0 :   }
     286                 :          0 :   return hDS;
     287                 :          0 : }
     288                 :            : 
     289                 :          0 : int CPL_STDCALL _gdalProgressFnWithFeedback( double dfComplete, const char *pszMessage, void *pProgressArg )
     290                 :            : {
     291                 :            :   Q_UNUSED( dfComplete )
     292                 :            :   Q_UNUSED( pszMessage )
     293                 :            : 
     294                 :          0 :   QgsRasterBlockFeedback *feedback = static_cast<QgsRasterBlockFeedback *>( pProgressArg );
     295                 :          0 :   return !feedback->isCanceled();
     296                 :            : }
     297                 :            : 
     298                 :            : 
     299                 :          0 : CPLErr QgsGdalProviderBase::gdalRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nPixelSpace, int nLineSpace, QgsRasterBlockFeedback *feedback )
     300                 :            : {
     301                 :            :   GDALRasterIOExtraArg extra;
     302                 :          0 :   INIT_RASTERIO_EXTRA_ARG( extra );
     303                 :            :   if ( false && feedback )  // disabled!
     304                 :            :   {
     305                 :            :     // Currently the cancellation is disabled... When RasterIO call is canceled,
     306                 :            :     // GDAL returns CE_Failure with error code = 0 (CPLE_None), however one would
     307                 :            :     // expect to get CPLE_UserInterrupt to clearly identify that the failure was
     308                 :            :     // caused by the cancellation and not that something dodgy is going on.
     309                 :            :     // Are both error codes acceptable?
     310                 :            :     extra.pfnProgress = _gdalProgressFnWithFeedback;
     311                 :            :     extra.pProgressData = ( void * ) feedback;
     312                 :            :   }
     313                 :          0 :   CPLErr err = GDALRasterIOEx( hBand, eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, &extra );
     314                 :            : 
     315                 :          0 :   return err;
     316                 :            : }
     317                 :            : 
     318                 :          0 : int QgsGdalProviderBase::gdalGetOverviewCount( GDALRasterBandH hBand )
     319                 :            : {
     320                 :          0 :   int count = GDALGetOverviewCount( hBand );
     321                 :          0 :   return count;
     322                 :            : }
     323                 :            : 
     324                 :          0 : QVariantMap QgsGdalProviderBase::decodeGdalUri( const QString &uri )
     325                 :            : {
     326                 :          0 :   QString path = uri;
     327                 :          0 :   QString layerName;
     328                 :          0 :   QStringList openOptions;
     329                 :            : 
     330                 :          0 :   QString vsiPrefix = qgsVsiPrefix( path );
     331                 :          0 :   QString vsiSuffix;
     332                 :          0 :   if ( path.startsWith( vsiPrefix, Qt::CaseInsensitive ) )
     333                 :            :   {
     334                 :          0 :     path = path.mid( vsiPrefix.count() );
     335                 :          0 :     if ( vsiPrefix == QLatin1String( "/vsizip/" ) )
     336                 :            :     {
     337                 :          0 :       const QRegularExpression vsiRegex( QStringLiteral( "(?:\\.zip|\\.tar|\\.gz|\\.tar\\.gz|\\.tgz)([^|]*)" ) );
     338                 :          0 :       QRegularExpressionMatch match = vsiRegex.match( path );
     339                 :          0 :       if ( match.hasMatch() )
     340                 :            :       {
     341                 :          0 :         vsiSuffix = match.captured( 1 );
     342                 :          0 :         path = path.remove( match.capturedStart( 1 ), match.capturedLength( 1 ) );
     343                 :          0 :       }
     344                 :          0 :     }
     345                 :          0 :   }
     346                 :            :   else
     347                 :            :   {
     348                 :          0 :     vsiPrefix.clear();
     349                 :            :   }
     350                 :            : 
     351                 :          0 :   if ( path.indexOf( ':' ) != -1 )
     352                 :            :   {
     353                 :          0 :     QStringList parts = path.split( ':' );
     354                 :          0 :     if ( parts[0].toLower() == QLatin1String( "gpkg" ) )
     355                 :            :     {
     356                 :          0 :       parts.removeFirst();
     357                 :            :       // Handle windows paths - which has an extra colon - and unix paths
     358                 :          0 :       if ( ( parts[0].length() > 1 && parts.count() > 1 ) || parts.count() > 2 )
     359                 :            :       {
     360                 :          0 :         layerName = parts[parts.length() - 1];
     361                 :          0 :         parts.removeLast();
     362                 :          0 :       }
     363                 :          0 :       path  = parts.join( ':' );
     364                 :          0 :     }
     365                 :          0 :   }
     366                 :            : 
     367                 :          0 :   if ( path.contains( '|' ) )
     368                 :            :   {
     369                 :          0 :     const QRegularExpression openOptionRegex( QStringLiteral( "\\|option:([^|]*)" ) );
     370                 :          0 :     while ( true )
     371                 :            :     {
     372                 :          0 :       QRegularExpressionMatch match = openOptionRegex.match( path );
     373                 :          0 :       if ( match.hasMatch() )
     374                 :            :       {
     375                 :          0 :         openOptions << match.captured( 1 );
     376                 :          0 :         path = path.remove( match.capturedStart( 0 ), match.capturedLength( 0 ) );
     377                 :          0 :       }
     378                 :            :       else
     379                 :            :       {
     380                 :          0 :         break;
     381                 :            :       }
     382                 :          0 :     }
     383                 :          0 :   }
     384                 :            : 
     385                 :          0 :   QVariantMap uriComponents;
     386                 :          0 :   uriComponents.insert( QStringLiteral( "path" ), path );
     387                 :          0 :   uriComponents.insert( QStringLiteral( "layerName" ), layerName );
     388                 :          0 :   if ( !openOptions.isEmpty() )
     389                 :          0 :     uriComponents.insert( QStringLiteral( "openOptions" ), openOptions );
     390                 :          0 :   if ( !vsiPrefix.isEmpty() )
     391                 :          0 :     uriComponents.insert( QStringLiteral( "vsiPrefix" ), vsiPrefix );
     392                 :          0 :   if ( !vsiSuffix.isEmpty() )
     393                 :          0 :     uriComponents.insert( QStringLiteral( "vsiSuffix" ), vsiSuffix );
     394                 :          0 :   return uriComponents;
     395                 :          0 : }
     396                 :            : 
     397                 :          0 : QString QgsGdalProviderBase::encodeGdalUri( const QVariantMap &parts )
     398                 :            : {
     399                 :          0 :   const QString vsiPrefix = parts.value( QStringLiteral( "vsiPrefix" ) ).toString();
     400                 :          0 :   const QString vsiSuffix = parts.value( QStringLiteral( "vsiSuffix" ) ).toString();
     401                 :          0 :   const QString path = parts.value( QStringLiteral( "path" ) ).toString();
     402                 :          0 :   const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
     403                 :            : 
     404                 :          0 :   QString uri = vsiPrefix + path + vsiSuffix;
     405                 :          0 :   if ( !layerName.isEmpty() && uri.endsWith( QLatin1String( "gpkg" ) ) )
     406                 :          0 :     uri = QStringLiteral( "GPKG:%1:%2" ).arg( uri, layerName );
     407                 :          0 :   else if ( !layerName.isEmpty() )
     408                 :          0 :     uri = uri + QStringLiteral( "|%1" ).arg( layerName );
     409                 :            : 
     410                 :          0 :   const QStringList openOptions = parts.value( QStringLiteral( "openOptions" ) ).toStringList();
     411                 :            : 
     412                 :          0 :   for ( const QString &openOption : openOptions )
     413                 :            :   {
     414                 :          0 :     uri += QLatin1String( "|option:" );
     415                 :          0 :     uri += openOption;
     416                 :            :   }
     417                 :            : 
     418                 :          0 :   return uri;
     419                 :          0 : }
     420                 :            : 
     421                 :            : ///@endcond

Generated by: LCOV version 1.14