LCOV - code coverage report
Current view: directory - frmts/webp - webpdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 298 212 71.1 %
Date: 2013-03-30 Functions: 20 14 70.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: webpdataset.cpp 25570 2013-01-27 00:22:37Z rouault $
       3                 :  *
       4                 :  * Project:  GDAL WEBP Driver
       5                 :  * Purpose:  Implement GDAL WEBP Support based on libwebp
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2011, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "gdal_pam.h"
      31                 : #include "cpl_string.h"
      32                 : 
      33                 : #include "webp/decode.h"
      34                 : #include "webp/encode.h"
      35                 : 
      36                 : CPL_CVSID("$Id: webpdataset.cpp 25570 2013-01-27 00:22:37Z rouault $");
      37                 : 
      38                 : CPL_C_START
      39                 : void    GDALRegister_WEBP(void);
      40                 : CPL_C_END
      41                 : 
      42                 : /************************************************************************/
      43                 : /* ==================================================================== */
      44                 : /*                               WEBPDataset                            */
      45                 : /* ==================================================================== */
      46                 : /************************************************************************/
      47                 : 
      48                 : class WEBPRasterBand;
      49                 : 
      50                 : class WEBPDataset : public GDALPamDataset
      51                 : {
      52                 :     friend class WEBPRasterBand;
      53                 : 
      54                 :     VSILFILE*   fpImage;
      55                 :     GByte* pabyUncompressed;
      56                 :     int    bHasBeenUncompressed;
      57                 :     CPLErr eUncompressErrRet;
      58                 :     CPLErr Uncompress();
      59                 : 
      60                 :     int    bHasReadXMPMetadata;
      61                 : 
      62                 :   public:
      63                 :                  WEBPDataset();
      64                 :                  ~WEBPDataset();
      65                 : 
      66                 :     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
      67                 :                                    void *, int, int, GDALDataType,
      68                 :                                    int, int *, int, int, int );
      69                 : 
      70                 :     virtual char  **GetMetadata( const char * pszDomain = "" );
      71                 : 
      72                 :     static GDALDataset *Open( GDALOpenInfo * );
      73                 :     static int          Identify( GDALOpenInfo * );
      74                 :     static GDALDataset* CreateCopy( const char * pszFilename,
      75                 :                                     GDALDataset *poSrcDS,
      76                 :                                     int bStrict, char ** papszOptions,
      77                 :                                     GDALProgressFunc pfnProgress,
      78                 :                                     void * pProgressData );
      79                 : };
      80                 : 
      81                 : /************************************************************************/
      82                 : /* ==================================================================== */
      83                 : /*                            WEBPRasterBand                            */
      84                 : /* ==================================================================== */
      85                 : /************************************************************************/
      86                 : 
      87                 : class WEBPRasterBand : public GDALPamRasterBand
      88              33 : {
      89                 :     friend class WEBPDataset;
      90                 : 
      91                 :   public:
      92                 : 
      93                 :                    WEBPRasterBand( WEBPDataset *, int );
      94                 : 
      95                 :     virtual CPLErr IReadBlock( int, int, void * );
      96                 :     virtual GDALColorInterp GetColorInterpretation();
      97                 : };
      98                 : 
      99                 : /************************************************************************/
     100                 : /*                          WEBPRasterBand()                            */
     101                 : /************************************************************************/
     102                 : 
     103              33 : WEBPRasterBand::WEBPRasterBand( WEBPDataset *poDS, int nBand )
     104                 : 
     105                 : {
     106              33 :     this->poDS = poDS;
     107                 : 
     108              33 :     eDataType = GDT_Byte;
     109                 : 
     110              33 :     nBlockXSize = poDS->nRasterXSize;
     111              33 :     nBlockYSize = 1;
     112              33 : }
     113                 : 
     114                 : /************************************************************************/
     115                 : /*                             IReadBlock()                             */
     116                 : /************************************************************************/
     117                 : 
     118             750 : CPLErr WEBPRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     119                 :                                   void * pImage )
     120                 : 
     121                 : {
     122             750 :     WEBPDataset* poGDS = (WEBPDataset*) poDS;
     123                 : 
     124             750 :     if( poGDS->Uncompress() != CE_None )
     125               0 :         return CE_Failure;
     126                 : 
     127                 :     int i;
     128                 :     GByte* pabyUncompressed =
     129             750 :         &poGDS->pabyUncompressed[nBlockYOff * nRasterXSize  * poGDS->nBands + nBand - 1];
     130          105450 :     for(i=0;i<nRasterXSize;i++)
     131          104700 :         ((GByte*)pImage)[i] = pabyUncompressed[poGDS->nBands * i];
     132                 : 
     133             750 :     return CE_None;
     134                 : }
     135                 : 
     136                 : /************************************************************************/
     137                 : /*                       GetColorInterpretation()                       */
     138                 : /************************************************************************/
     139                 : 
     140              18 : GDALColorInterp WEBPRasterBand::GetColorInterpretation()
     141                 : 
     142                 : {
     143              18 :     if ( nBand == 1 )
     144               5 :         return GCI_RedBand;
     145                 : 
     146              13 :     else if( nBand == 2 )
     147               5 :         return GCI_GreenBand;
     148                 : 
     149               8 :     else if ( nBand == 3 )
     150               5 :         return GCI_BlueBand;
     151                 : 
     152                 :     else
     153               3 :         return GCI_AlphaBand;
     154                 : }
     155                 : 
     156                 : /************************************************************************/
     157                 : /* ==================================================================== */
     158                 : /*                             WEBPDataset                               */
     159                 : /* ==================================================================== */
     160                 : /************************************************************************/
     161                 : 
     162                 : 
     163                 : /************************************************************************/
     164                 : /*                            WEBPDataset()                              */
     165                 : /************************************************************************/
     166                 : 
     167              10 : WEBPDataset::WEBPDataset()
     168                 : 
     169                 : {
     170              10 :     fpImage = NULL;
     171              10 :     pabyUncompressed = NULL;
     172              10 :     bHasBeenUncompressed = FALSE;
     173              10 :     eUncompressErrRet = CE_None;
     174              10 :     bHasReadXMPMetadata = FALSE;
     175              10 : }
     176                 : 
     177                 : /************************************************************************/
     178                 : /*                           ~WEBPDataset()                             */
     179                 : /************************************************************************/
     180                 : 
     181              10 : WEBPDataset::~WEBPDataset()
     182                 : 
     183                 : {
     184              10 :     FlushCache();
     185              10 :     if (fpImage)
     186              10 :         VSIFCloseL(fpImage);
     187              10 :     VSIFree(pabyUncompressed);
     188              10 : }
     189                 : 
     190                 : /************************************************************************/
     191                 : /*                           GetMetadata()                              */
     192                 : /************************************************************************/
     193                 : 
     194               5 : char  **WEBPDataset::GetMetadata( const char * pszDomain )
     195                 : {
     196               5 :     if ((pszDomain != NULL && EQUAL(pszDomain, "xml:XMP")) && !bHasReadXMPMetadata)
     197                 :     {
     198               2 :         bHasReadXMPMetadata = TRUE;
     199                 : 
     200               2 :         VSIFSeekL(fpImage, 12, SEEK_SET);
     201                 : 
     202               2 :         int bFirst = TRUE;
     203               2 :         while(TRUE)
     204                 :         {
     205                 :             char szHeader[5];
     206                 :             GUInt32 nChunkSize;
     207                 : 
     208               4 :             if (VSIFReadL(szHeader, 1, 4, fpImage) != 4 ||
     209                 :                 VSIFReadL(&nChunkSize, 1, 4, fpImage) != 4)
     210               0 :                 break;
     211                 : 
     212               4 :             szHeader[4] = '\0';
     213                 :             CPL_LSBPTR32(&nChunkSize);
     214                 : 
     215               4 :             if (bFirst)
     216                 :             {
     217               2 :                 if (strcmp(szHeader, "VP8X") != 0 || nChunkSize < 10)
     218               1 :                     break;
     219                 : 
     220                 :                 int nFlags;
     221               1 :                 if (VSIFReadL(&nFlags, 1, 4, fpImage) != 4)
     222               0 :                     break;
     223                 :                 CPL_LSBPTR32(&nFlags);
     224               1 :                 if ((nFlags & 8) == 0)
     225               0 :                     break;
     226                 : 
     227               1 :                 VSIFSeekL(fpImage, nChunkSize - 4, SEEK_CUR);
     228                 : 
     229               1 :                 bFirst = FALSE;
     230                 :             }
     231               2 :             else if (strcmp(szHeader, "META") == 0)
     232                 :             {
     233               1 :                 if (nChunkSize > 1024 * 1024)
     234               0 :                     break;
     235                 : 
     236               1 :                 char* pszXMP = (char*) VSIMalloc(nChunkSize + 1);
     237               1 :                 if (pszXMP == NULL)
     238               0 :                     break;
     239                 : 
     240               1 :                 if ((GUInt32)VSIFReadL(pszXMP, 1, nChunkSize, fpImage) != nChunkSize)
     241                 :                 {
     242               0 :                     VSIFree(pszXMP);
     243               0 :                     break;
     244                 :                 }
     245               1 :                 pszXMP[nChunkSize] = '\0';
     246                 : 
     247                 :                 /* Avoid setting the PAM dirty bit just for that */
     248               1 :                 int nOldPamFlags = nPamFlags;
     249                 : 
     250                 :                 char *apszMDList[2];
     251               1 :                 apszMDList[0] = pszXMP;
     252               1 :                 apszMDList[1] = NULL;
     253               1 :                 SetMetadata(apszMDList, "xml:XMP");
     254                 : 
     255               1 :                 nPamFlags = nOldPamFlags;
     256                 : 
     257               1 :                 VSIFree(pszXMP);
     258               1 :                 break;
     259                 :             }
     260                 :             else
     261               1 :                 VSIFSeekL(fpImage, nChunkSize, SEEK_CUR);
     262                 :         }
     263                 :     }
     264                 : 
     265               5 :     return GDALPamDataset::GetMetadata(pszDomain);
     266                 : }
     267                 : 
     268                 : /************************************************************************/
     269                 : /*                            Uncompress()                              */
     270                 : /************************************************************************/
     271                 : 
     272             750 : CPLErr WEBPDataset::Uncompress()
     273                 : {
     274             750 :     if (bHasBeenUncompressed)
     275             745 :         return eUncompressErrRet;
     276               5 :     bHasBeenUncompressed = TRUE;
     277               5 :     eUncompressErrRet = CE_Failure;
     278                 : 
     279               5 :     VSIFSeekL(fpImage, 0, SEEK_END);
     280               5 :     vsi_l_offset nSize = VSIFTellL(fpImage);
     281               5 :     if (nSize != (vsi_l_offset)(uint32_t)nSize)
     282               0 :         return CE_Failure;
     283               5 :     VSIFSeekL(fpImage, 0, SEEK_SET);
     284               5 :     uint8_t* pabyCompressed = (uint8_t*)VSIMalloc(nSize);
     285               5 :     if (pabyCompressed == NULL)
     286               0 :         return CE_Failure;
     287               5 :     VSIFReadL(pabyCompressed, 1, nSize, fpImage);
     288                 :     uint8_t* pRet;
     289                 : 
     290               5 :     if (nBands == 4)
     291                 :         pRet = WebPDecodeRGBAInto(pabyCompressed, (uint32_t)nSize,
     292                 :                         (uint8_t*)pabyUncompressed, nRasterXSize * nRasterYSize * nBands,
     293               2 :                         nRasterXSize * nBands);
     294                 :     else
     295                 :         pRet = WebPDecodeRGBInto(pabyCompressed, (uint32_t)nSize,
     296                 :                         (uint8_t*)pabyUncompressed, nRasterXSize * nRasterYSize * nBands,
     297               3 :                         nRasterXSize * nBands);
     298               5 :     VSIFree(pabyCompressed);
     299               5 :     if (pRet == NULL)
     300                 :     {
     301                 :         CPLError(CE_Failure, CPLE_AppDefined,
     302               0 :                     "WebPDecodeRGBInto() failed");
     303               0 :         return CE_Failure;
     304                 :     }
     305               5 :     eUncompressErrRet = CE_None;
     306                 : 
     307               5 :     return CE_None;
     308                 : }
     309                 : 
     310                 : /************************************************************************/
     311                 : /*                             IRasterIO()                              */
     312                 : /************************************************************************/
     313                 : 
     314               0 : CPLErr WEBPDataset::IRasterIO( GDALRWFlag eRWFlag,
     315                 :                               int nXOff, int nYOff, int nXSize, int nYSize,
     316                 :                               void *pData, int nBufXSize, int nBufYSize,
     317                 :                               GDALDataType eBufType,
     318                 :                               int nBandCount, int *panBandMap,
     319                 :                               int nPixelSpace, int nLineSpace, int nBandSpace )
     320                 : 
     321                 : {
     322               0 :     if((eRWFlag == GF_Read) &&
     323                 :        (nBandCount == nBands) &&
     324                 :        (nXOff == 0) && (nXOff == 0) &&
     325                 :        (nXSize == nBufXSize) && (nXSize == nRasterXSize) &&
     326                 :        (nYSize == nBufYSize) && (nYSize == nRasterYSize) &&
     327                 :        (eBufType == GDT_Byte) && 
     328                 :        (nPixelSpace == nBands) &&
     329                 :        (nLineSpace == (nPixelSpace*nXSize)) &&
     330                 :        (nBandSpace == 1) &&
     331                 :        (pData != NULL) &&
     332                 :        (panBandMap != NULL) &&
     333               0 :        (panBandMap[0] == 1) && (panBandMap[1] == 2) && (panBandMap[2] == 3) && (nBands == 3 || panBandMap[3] == 4))
     334                 :     {
     335               0 :         Uncompress();
     336               0 :         memcpy(pData, pabyUncompressed, nBands * nXSize * nYSize);
     337               0 :         return CE_None;
     338                 :     }
     339                 : 
     340                 :     return GDALPamDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     341                 :                                      pData, nBufXSize, nBufYSize, eBufType,
     342                 :                                      nBandCount, panBandMap,
     343               0 :                                      nPixelSpace, nLineSpace, nBandSpace);
     344                 : }
     345                 : 
     346                 : /************************************************************************/
     347                 : /*                              Identify()                              */
     348                 : /************************************************************************/
     349                 : 
     350           11444 : int WEBPDataset::Identify( GDALOpenInfo * poOpenInfo )
     351                 : 
     352                 : {
     353           11444 :     GByte  *pabyHeader = NULL;
     354           11444 :     int    nHeaderBytes = poOpenInfo->nHeaderBytes;
     355                 : 
     356           11444 :     pabyHeader = poOpenInfo->pabyHeader;
     357                 : 
     358           11444 :     if( nHeaderBytes < 20 )
     359           11251 :         return FALSE;
     360                 : 
     361                 :     return memcmp(pabyHeader, "RIFF", 4) == 0 &&
     362                 :            memcmp(pabyHeader + 8, "WEBP", 4) == 0 &&
     363                 :            (memcmp(pabyHeader + 12, "VP8 ", 4) == 0 ||
     364                 :             memcmp(pabyHeader + 12, "VP8L", 4) == 0 ||
     365             193 :             memcmp(pabyHeader + 12, "VP8X", 4) == 0);
     366                 : }
     367                 : 
     368                 : /************************************************************************/
     369                 : /*                                Open()                                */
     370                 : /************************************************************************/
     371                 : 
     372            1342 : GDALDataset *WEBPDataset::Open( GDALOpenInfo * poOpenInfo )
     373                 : 
     374                 : {
     375            1342 :     if( !Identify( poOpenInfo ) )
     376            1332 :         return NULL;
     377                 : 
     378                 :     int nWidth, nHeight;
     379              10 :     if (!WebPGetInfo((const uint8_t*)poOpenInfo->pabyHeader, (uint32_t)poOpenInfo->nHeaderBytes,
     380                 :                      &nWidth, &nHeight))
     381               0 :         return NULL;
     382                 : 
     383              10 :     int nBands = 3;
     384                 : 
     385                 : #if WEBP_DECODER_ABI_VERSION >= 0x0002
     386                 :      WebPDecoderConfig config;
     387              10 :      if (!WebPInitDecoderConfig(&config))
     388               0 :          return NULL;
     389                 : 
     390              10 :      int bOK = WebPGetFeatures(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes, &config.input) == VP8_STATUS_OK;
     391                 : 
     392              10 :     if (config.input.has_alpha)
     393               3 :         nBands = 4;
     394                 : 
     395              10 :      WebPFreeDecBuffer(&config.output);
     396                 : 
     397              10 :     if (!bOK)
     398               0 :         return NULL;
     399                 : 
     400                 : #endif
     401                 : 
     402              10 :     if( poOpenInfo->eAccess == GA_Update )
     403                 :     {
     404                 :         CPLError( CE_Failure, CPLE_NotSupported,
     405                 :                   "The WEBP driver does not support update access to existing"
     406               0 :                   " datasets.\n" );
     407               0 :         return NULL;
     408                 :     }
     409                 : 
     410                 : /* -------------------------------------------------------------------- */
     411                 : /*      Open the file using the large file api.                         */
     412                 : /* -------------------------------------------------------------------- */
     413              10 :     VSILFILE* fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
     414                 : 
     415              10 :     if( fpImage == NULL )
     416               0 :         return NULL;
     417                 : 
     418              10 :     GByte* pabyUncompressed = (GByte*)VSIMalloc3(nWidth, nHeight, nBands);
     419              10 :     if (pabyUncompressed == NULL)
     420                 :     {
     421               0 :         VSIFCloseL(fpImage);
     422               0 :         return NULL;
     423                 :     }
     424                 : 
     425                 : /* -------------------------------------------------------------------- */
     426                 : /*      Create a corresponding GDALDataset.                             */
     427                 : /* -------------------------------------------------------------------- */
     428                 :     WEBPDataset  *poDS;
     429                 : 
     430              10 :     poDS = new WEBPDataset();
     431              10 :     poDS->nRasterXSize = nWidth;
     432              10 :     poDS->nRasterYSize = nHeight;
     433              10 :     poDS->fpImage = fpImage;
     434              10 :     poDS->pabyUncompressed = pabyUncompressed;
     435                 : 
     436                 : /* -------------------------------------------------------------------- */
     437                 : /*      Create band information objects.                                */
     438                 : /* -------------------------------------------------------------------- */
     439              86 :     for( int iBand = 0; iBand < nBands; iBand++ )
     440              33 :         poDS->SetBand( iBand+1, new WEBPRasterBand( poDS, iBand+1 ) );
     441                 : 
     442                 : /* -------------------------------------------------------------------- */
     443                 : /*      Initialize any PAM information.                                 */
     444                 : /* -------------------------------------------------------------------- */
     445              10 :     poDS->SetDescription( poOpenInfo->pszFilename );
     446                 : 
     447              10 :     poDS->TryLoadXML( poOpenInfo->papszSiblingFiles );
     448                 : 
     449                 : /* -------------------------------------------------------------------- */
     450                 : /*      Open overviews.                                                 */
     451                 : /* -------------------------------------------------------------------- */
     452              10 :     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
     453                 : 
     454              10 :     return poDS;
     455                 : }
     456                 : 
     457                 : /************************************************************************/
     458                 : /*                              WebPUserData                            */
     459                 : /************************************************************************/
     460                 : 
     461                 : typedef struct
     462                 : {
     463                 :     VSILFILE         *fp;
     464                 :     GDALProgressFunc  pfnProgress;
     465                 :     void             *pProgressData;
     466                 : } WebPUserData;
     467                 : 
     468                 : /************************************************************************/
     469                 : /*                         WEBPDatasetWriter()                          */
     470                 : /************************************************************************/
     471                 : 
     472                 : static
     473              31 : int WEBPDatasetWriter(const uint8_t* data, size_t data_size,
     474                 :                       const WebPPicture* const picture)
     475                 : {
     476              31 :     WebPUserData* pUserData = (WebPUserData*)picture->custom_ptr;
     477              31 :     return VSIFWriteL(data, 1, data_size, pUserData->fp) == data_size;
     478                 : }
     479                 : 
     480                 : /************************************************************************/
     481                 : /*                        WEBPDatasetProgressHook()                     */
     482                 : /************************************************************************/
     483                 : 
     484                 : static
     485              54 : int WEBPDatasetProgressHook(int percent, const WebPPicture* const picture)
     486                 : {
     487              54 :     WebPUserData* pUserData = (WebPUserData*)picture->custom_ptr;
     488              54 :     return pUserData->pfnProgress( percent / 100.0, NULL, pUserData->pProgressData );
     489                 : }
     490                 : 
     491                 : /************************************************************************/
     492                 : /*                              CreateCopy()                            */
     493                 : /************************************************************************/
     494                 : 
     495                 : GDALDataset *
     496              23 : WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     497                 :                         int bStrict, char ** papszOptions,
     498                 :                         GDALProgressFunc pfnProgress, void * pProgressData )
     499                 : 
     500                 : {
     501              23 :     int  nBands = poSrcDS->GetRasterCount();
     502              23 :     int  nXSize = poSrcDS->GetRasterXSize();
     503              23 :     int  nYSize = poSrcDS->GetRasterYSize();
     504                 : 
     505                 : /* -------------------------------------------------------------------- */
     506                 : /*      WEBP library initialization                                     */
     507                 : /* -------------------------------------------------------------------- */
     508                 : 
     509                 :     WebPPicture sPicture;
     510              23 :     if (!WebPPictureInit(&sPicture))
     511                 :     {
     512               0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureInit() failed");
     513               0 :         return NULL;
     514                 :     }
     515                 : 
     516                 : /* -------------------------------------------------------------------- */
     517                 : /*      Some some rudimentary checks                                    */
     518                 : /* -------------------------------------------------------------------- */
     519                 : 
     520              23 :     if( nXSize > 16383 || nYSize > 16383 )
     521                 :     {
     522                 :         CPLError( CE_Failure, CPLE_NotSupported,
     523               0 :                   "WEBP maximum image dimensions are 16383 x 16383.");
     524                 : 
     525               0 :         return NULL;
     526                 :     }
     527                 : 
     528              23 :     if( nBands != 3
     529                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     530                 :         && nBands != 4
     531                 : #endif
     532                 :         )
     533                 :     {
     534                 :         CPLError( CE_Failure, CPLE_NotSupported,
     535                 :                   "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
     536                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     537                 :                   "or 4 (RGBA) "
     538                 : #endif
     539                 :                   "bands.",
     540              14 :                   nBands );
     541                 : 
     542              14 :         return NULL;
     543                 :     }
     544                 : 
     545               9 :     GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     546                 : 
     547               9 :     if( eDT != GDT_Byte )
     548                 :     {
     549                 :         CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
     550                 :                   "WEBP driver doesn't support data type %s. "
     551                 :                   "Only eight bit byte bands supported.",
     552                 :                   GDALGetDataTypeName(
     553               0 :                       poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
     554                 : 
     555               0 :         if (bStrict)
     556               0 :             return NULL;
     557                 :     }
     558                 : 
     559                 : /* -------------------------------------------------------------------- */
     560                 : /*      What options has the user selected?                             */
     561                 : /* -------------------------------------------------------------------- */
     562               9 :     float fQuality = 75.0f;
     563               9 :     const char* pszQUALITY = CSLFetchNameValue(papszOptions, "QUALITY"); 
     564               9 :     if( pszQUALITY != NULL )
     565                 :     {
     566               1 :         fQuality = (float) atof(pszQUALITY);
     567               1 :         if( fQuality < 0.0f || fQuality > 100.0f )
     568                 :         {
     569                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     570               0 :                       "%s=%s is not a legal value.", "QUALITY", pszQUALITY);
     571               0 :             return NULL;
     572                 :         }
     573                 :     }
     574                 : 
     575               9 :     WebPPreset nPreset = WEBP_PRESET_DEFAULT;
     576               9 :     const char* pszPRESET = CSLFetchNameValueDef(papszOptions, "PRESET", "DEFAULT");
     577               9 :     if (EQUAL(pszPRESET, "DEFAULT"))
     578               9 :         nPreset = WEBP_PRESET_DEFAULT;
     579               0 :     else if (EQUAL(pszPRESET, "PICTURE"))
     580               0 :         nPreset = WEBP_PRESET_PICTURE;
     581               0 :     else if (EQUAL(pszPRESET, "PHOTO"))
     582               0 :         nPreset = WEBP_PRESET_PHOTO;
     583               0 :     else if (EQUAL(pszPRESET, "PICTURE"))
     584               0 :         nPreset = WEBP_PRESET_PICTURE;
     585               0 :     else if (EQUAL(pszPRESET, "DRAWING"))
     586               0 :         nPreset = WEBP_PRESET_DRAWING;
     587               0 :     else if (EQUAL(pszPRESET, "ICON"))
     588               0 :         nPreset = WEBP_PRESET_ICON;
     589               0 :     else if (EQUAL(pszPRESET, "TEXT"))
     590               0 :         nPreset = WEBP_PRESET_TEXT;
     591                 :     else
     592                 :     {
     593                 :         CPLError( CE_Failure, CPLE_IllegalArg,
     594               0 :                   "%s=%s is not a legal value.", "PRESET", pszPRESET );
     595               0 :         return NULL;
     596                 :     }
     597                 : 
     598                 :     WebPConfig sConfig;
     599               9 :     if (!WebPConfigInitInternal(&sConfig, nPreset, fQuality, WEBP_ENCODER_ABI_VERSION))
     600                 :     {
     601               0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPConfigInit() failed");
     602               0 :         return NULL;
     603                 :     }
     604                 : 
     605                 : 
     606                 : #define FETCH_AND_SET_OPTION_INT(name, fieldname, minval, maxval) \
     607                 : { \
     608                 :     const char* pszVal = CSLFetchNameValue(papszOptions, name); \
     609                 :     if (pszVal != NULL) \
     610                 :     { \
     611                 :         sConfig.fieldname = atoi(pszVal); \
     612                 :         if (sConfig.fieldname < minval || sConfig.fieldname > maxval) \
     613                 :         { \
     614                 :             CPLError( CE_Failure, CPLE_IllegalArg, \
     615                 :                       "%s=%s is not a legal value.", name, pszVal ); \
     616                 :             return NULL; \
     617                 :         } \
     618                 :     } \
     619                 : }
     620                 : 
     621               9 :     FETCH_AND_SET_OPTION_INT("TARGETSIZE", target_size, 0, INT_MAX);
     622                 : 
     623               9 :     const char* pszPSNR = CSLFetchNameValue(papszOptions, "PSNR");
     624               9 :     if (pszPSNR)
     625                 :     {
     626               0 :         sConfig.target_PSNR = atof(pszPSNR);
     627               0 :         if (sConfig.target_PSNR < 0)
     628                 :         {
     629                 :             CPLError( CE_Failure, CPLE_IllegalArg,
     630               0 :                       "PSNR=%s is not a legal value.", pszPSNR );
     631               0 :             return NULL;
     632                 :         }
     633                 :     }
     634                 : 
     635               9 :     FETCH_AND_SET_OPTION_INT("METHOD", method, 0, 6);
     636               9 :     FETCH_AND_SET_OPTION_INT("SEGMENTS", segments, 1, 4);
     637               9 :     FETCH_AND_SET_OPTION_INT("SNS_STRENGTH", sns_strength, 0, 100);
     638               9 :     FETCH_AND_SET_OPTION_INT("FILTER_STRENGTH", filter_strength, 0, 100);
     639               9 :     FETCH_AND_SET_OPTION_INT("FILTER_SHARPNESS", filter_sharpness, 0, 7);
     640               9 :     FETCH_AND_SET_OPTION_INT("FILTER_TYPE", filter_type, 0, 1);
     641               9 :     FETCH_AND_SET_OPTION_INT("AUTOFILTER", autofilter, 0, 1);
     642               9 :     FETCH_AND_SET_OPTION_INT("PASS", pass, 1, 10);
     643               9 :     FETCH_AND_SET_OPTION_INT("PREPROCESSING", preprocessing, 0, 1);
     644               9 :     FETCH_AND_SET_OPTION_INT("PARTITIONS", partitions, 0, 3);
     645                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0002
     646               9 :     FETCH_AND_SET_OPTION_INT("PARTITION_LIMIT", partition_limit, 0, 100);
     647                 : #endif
     648                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     649               9 :     sConfig.lossless = CSLFetchBoolean(papszOptions, "LOSSLESS", FALSE);
     650               9 :     if (sConfig.lossless)
     651               1 :         sPicture.use_argb = 1;
     652                 : #endif
     653                 : 
     654               9 :     if (!WebPValidateConfig(&sConfig))
     655                 :     {
     656               0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPValidateConfig() failed");
     657               0 :         return NULL;
     658                 :     }
     659                 : 
     660                 : /* -------------------------------------------------------------------- */
     661                 : /*      Allocate memory                                                 */
     662                 : /* -------------------------------------------------------------------- */
     663                 :     GByte   *pabyBuffer;
     664                 : 
     665               9 :     pabyBuffer = (GByte *) VSIMalloc( nBands * nXSize * nYSize );
     666               9 :     if (pabyBuffer == NULL)
     667                 :     {
     668               0 :         return NULL;
     669                 :     }
     670                 : 
     671                 : /* -------------------------------------------------------------------- */
     672                 : /*      Create the dataset.                                             */
     673                 : /* -------------------------------------------------------------------- */
     674                 :     VSILFILE    *fpImage;
     675                 : 
     676               9 :     fpImage = VSIFOpenL( pszFilename, "wb" );
     677               9 :     if( fpImage == NULL )
     678                 :     {
     679                 :         CPLError( CE_Failure, CPLE_OpenFailed,
     680                 :                   "Unable to create WEBP file %s.\n",
     681               4 :                   pszFilename );
     682               4 :         VSIFree(pabyBuffer);
     683               4 :         return NULL;
     684                 :     }
     685                 : 
     686                 :     WebPUserData sUserData;
     687               5 :     sUserData.fp = fpImage;
     688               5 :     sUserData.pfnProgress = pfnProgress ? pfnProgress : GDALDummyProgress;
     689               5 :     sUserData.pProgressData = pProgressData;
     690                 : 
     691                 : /* -------------------------------------------------------------------- */
     692                 : /*      WEBP library settings                                           */
     693                 : /* -------------------------------------------------------------------- */
     694                 : 
     695               5 :     sPicture.width = nXSize;
     696               5 :     sPicture.height = nYSize;
     697               5 :     sPicture.writer = WEBPDatasetWriter;
     698               5 :     sPicture.custom_ptr = &sUserData;
     699                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     700               5 :     sPicture.progress_hook = WEBPDatasetProgressHook;
     701                 : #endif
     702               5 :     if (!WebPPictureAlloc(&sPicture))
     703                 :     {
     704               0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureAlloc() failed");
     705               0 :         VSIFree(pabyBuffer);
     706               0 :         VSIFCloseL( fpImage );
     707               0 :         return NULL;
     708                 :     }
     709                 : 
     710                 : /* -------------------------------------------------------------------- */
     711                 : /*      Acquire source imagery.                                         */
     712                 : /* -------------------------------------------------------------------- */
     713               5 :     CPLErr      eErr = CE_None;
     714                 : 
     715                 :     eErr = poSrcDS->RasterIO( GF_Read, 0, 0, nXSize, nYSize,
     716                 :                               pabyBuffer, nXSize, nYSize, GDT_Byte,
     717                 :                               nBands, NULL,
     718               5 :                               nBands, nBands * nXSize, 1 );
     719                 : 
     720                 : /* -------------------------------------------------------------------- */
     721                 : /*      Import and write to file                                        */
     722                 : /* -------------------------------------------------------------------- */
     723                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     724               8 :     if (eErr == CE_None && nBands == 4)
     725                 :     {
     726               3 :         if (!WebPPictureImportRGBA(&sPicture, pabyBuffer, nBands * nXSize))
     727                 :         {
     728               0 :             CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGBA() failed");
     729               0 :             eErr = CE_Failure;
     730                 :         }
     731                 :     }
     732                 :     else
     733                 : #endif
     734               2 :     if (eErr == CE_None &&
     735                 :         !WebPPictureImportRGB(&sPicture, pabyBuffer, nBands * nXSize))
     736                 :     {
     737               0 :         CPLError(CE_Failure, CPLE_AppDefined, "WebPPictureImportRGB() failed");
     738               0 :         eErr = CE_Failure;
     739                 :     }
     740                 : 
     741               5 :     if (eErr == CE_None && !WebPEncode(&sConfig, &sPicture))
     742                 :     {
     743               0 :         const char* pszErrorMsg = NULL;
     744                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     745               0 :         switch(sPicture.error_code)
     746                 :         {
     747               0 :             case VP8_ENC_ERROR_OUT_OF_MEMORY: pszErrorMsg = "Out of memory"; break;
     748               0 :             case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY: pszErrorMsg = "Out of memory while flushing bits"; break;
     749               0 :             case VP8_ENC_ERROR_NULL_PARAMETER: pszErrorMsg = "A pointer parameter is NULL"; break;
     750               0 :             case VP8_ENC_ERROR_INVALID_CONFIGURATION: pszErrorMsg = "Configuration is invalid"; break;
     751               0 :             case VP8_ENC_ERROR_BAD_DIMENSION: pszErrorMsg = "Picture has invalid width/height"; break;
     752               0 :             case VP8_ENC_ERROR_PARTITION0_OVERFLOW: pszErrorMsg = "Partition is bigger than 512k. Try using less SEGMENTS, or increase PARTITION_LIMIT value"; break;
     753               0 :             case VP8_ENC_ERROR_PARTITION_OVERFLOW: pszErrorMsg = "Partition is bigger than 16M"; break;
     754               0 :             case VP8_ENC_ERROR_BAD_WRITE: pszErrorMsg = "Error while flusing bytes"; break;
     755               0 :             case VP8_ENC_ERROR_FILE_TOO_BIG: pszErrorMsg = "File is bigger than 4G"; break;
     756               0 :             case VP8_ENC_ERROR_USER_ABORT: pszErrorMsg = "User interrupted"; break;
     757                 :             default: break;
     758                 :         }
     759                 : #endif
     760               0 :         if (pszErrorMsg)
     761               0 :             CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed : %s", pszErrorMsg);
     762                 :         else
     763               0 :             CPLError(CE_Failure, CPLE_AppDefined, "WebPEncode() failed");
     764               0 :         eErr = CE_Failure;
     765                 :     }
     766                 : 
     767                 : /* -------------------------------------------------------------------- */
     768                 : /*      Cleanup and close.                                              */
     769                 : /* -------------------------------------------------------------------- */
     770               5 :     CPLFree( pabyBuffer );
     771                 : 
     772               5 :     WebPPictureFree(&sPicture);
     773                 : 
     774               5 :     VSIFCloseL( fpImage );
     775                 : 
     776               5 :     if( eErr != CE_None )
     777                 :     {
     778               0 :         VSIUnlink( pszFilename );
     779               0 :         return NULL;
     780                 :     }
     781                 : 
     782                 : /* -------------------------------------------------------------------- */
     783                 : /*      Re-open dataset, and copy any auxilary pam information.         */
     784                 : /* -------------------------------------------------------------------- */
     785               5 :     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     786                 : 
     787                 :     /* If outputing to stdout, we can't reopen it, so we'll return */
     788                 :     /* a fake dataset to make the caller happy */
     789               5 :     CPLPushErrorHandler(CPLQuietErrorHandler);
     790               5 :     WEBPDataset *poDS = (WEBPDataset*) WEBPDataset::Open( &oOpenInfo );
     791               5 :     CPLPopErrorHandler();
     792               5 :     if( poDS )
     793                 :     {
     794               5 :         poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
     795               5 :         return poDS;
     796                 :     }
     797                 : 
     798               0 :     return NULL;
     799                 : }
     800                 : 
     801                 : /************************************************************************/
     802                 : /*                         GDALRegister_WEBP()                          */
     803                 : /************************************************************************/
     804                 : 
     805             610 : void GDALRegister_WEBP()
     806                 : 
     807                 : {
     808                 :     GDALDriver  *poDriver;
     809                 : 
     810             610 :     if( GDALGetDriverByName( "WEBP" ) == NULL )
     811                 :     {
     812             588 :         poDriver = new GDALDriver();
     813                 : 
     814             588 :         poDriver->SetDescription( "WEBP" );
     815                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
     816             588 :                                    "WEBP" );
     817                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
     818             588 :                                    "frmt_webp.html" );
     819             588 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "webp" );
     820             588 :         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/webp" );
     821                 : 
     822                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
     823             588 :                                    "Byte" );
     824                 : 
     825                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
     826                 : "<CreationOptionList>\n"
     827                 : "   <Option name='QUALITY' type='float' description='good=100, bad=0' default='75'/>\n"
     828                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     829                 : "   <Option name='LOSSLESS' type='boolean' description='Whether lossless compression should be used' default='FALSE'/>\n"
     830                 : #endif
     831                 : "   <Option name='PRESET' type='string-select' description='kind of image' default='DEFAULT'>\n"
     832                 : "       <Value>DEFAULT</Value>\n"
     833                 : "       <Value>PICTURE</Value>\n"
     834                 : "       <Value>PHOTO</Value>\n"
     835                 : "       <Value>DRAWING</Value>\n"
     836                 : "       <Value>ICON</Value>\n"
     837                 : "       <Value>TEXT</Value>\n"
     838                 : "   </Option>\n"
     839                 : "   <Option name='TARGETSIZE' type='int' description='if non-zero, desired target size in bytes. Has precedence over QUALITY'/>\n"
     840                 : "   <Option name='PSNR' type='float' description='if non-zero, minimal distortion to to achieve. Has precedence over TARGETSIZE'/>\n"
     841                 : "   <Option name='METHOD' type='int' description='quality/speed trade-off. fast=0, slower-better=6' default='4'/>\n"
     842                 : "   <Option name='SEGMENTS' type='int' description='maximum number of segments [1-4]' default='4'/>\n"
     843                 : "   <Option name='SNS_STRENGTH' type='int' description='Spatial Noise Shaping. off=0, maximum=100' default='50'/>\n"
     844                 : "   <Option name='FILTER_STRENGTH' type='int' description='Filter strength. off=0, strongest=100' default='20'/>\n"
     845                 : "   <Option name='FILTER_SHARPNESS' type='int' description='Filter sharpness. off=0, least sharp=7' default='0'/>\n"
     846                 : "   <Option name='FILTER_TYPE' type='int' description='Filtering type. simple=0, strong=1' default='0'/>\n"
     847                 : "   <Option name='AUTOFILTER' type='int' description=\"Auto adjust filter's strength. off=0, on=1\" default='0'/>\n"
     848                 : "   <Option name='PASS' type='int' description='Number of entropy analysis passes [1-10]' default='1'/>\n"
     849                 : "   <Option name='PREPROCESSING' type='int' description='Preprocessing filter. none=0, segment-smooth=1' default='0'/>\n"
     850                 : "   <Option name='PARTITIONS' type='int' description='log2(number of token partitions) in [0..3]' default='0'/>\n"
     851                 : #if WEBP_ENCODER_ABI_VERSION >= 0x0002
     852                 : "   <Option name='PARTITION_LIMIT' type='int' description='quality degradation allowed to fit the 512k limit on prediction modes coding (0=no degradation, 100=full)' default='0'/>\n"
     853                 : #endif
     854             588 : "</CreationOptionList>\n" );
     855                 : 
     856             588 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
     857                 : 
     858             588 :         poDriver->pfnIdentify = WEBPDataset::Identify;
     859             588 :         poDriver->pfnOpen = WEBPDataset::Open;
     860             588 :         poDriver->pfnCreateCopy = WEBPDataset::CreateCopy;
     861                 : 
     862             588 :         GetGDALDriverManager()->RegisterDriver( poDriver );
     863                 :     }
     864             610 : }

Generated by: LCOV version 1.7