LCOV - code coverage report
Current view: directory - frmts/webp - webpdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 293 208 71.0 %
Date: 2012-12-26 Functions: 20 14 70.0 %

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

Generated by: LCOV version 1.7