LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_webp.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 256 410 62.4 %
Date: 2026-04-23 19:47:11 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018, Mapbox
       3             :  * Author: <norman.barker at mapbox.com>
       4             :  *
       5             :  * Permission to use, copy, modify, distribute, and sell this software and
       6             :  * its documentation for any purpose is hereby granted without fee, provided
       7             :  * that (i) the above copyright notices and this permission notice appear in
       8             :  * all copies of the software and related documentation, and (ii) the names of
       9             :  * Sam Leffler and Silicon Graphics may not be used in any advertising or
      10             :  * publicity relating to the software without the specific, prior written
      11             :  * permission of Sam Leffler and Silicon Graphics.
      12             :  *
      13             :  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
      14             :  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
      15             :  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
      16             :  *
      17             :  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
      18             :  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
      19             :  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
      20             :  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
      21             :  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
      22             :  * OF THIS SOFTWARE.
      23             :  */
      24             : 
      25             : #include "tiffiop.h"
      26             : #ifdef WEBP_SUPPORT
      27             : /*
      28             :  * TIFF Library.
      29             :  *
      30             :  * WEBP Compression Support
      31             :  *
      32             :  */
      33             : 
      34             : #include "webp/decode.h"
      35             : #include "webp/encode.h"
      36             : 
      37             : #include <stdbool.h>
      38             : #include <stdio.h>
      39             : 
      40             : #define LSTATE_INIT_DECODE 0x01
      41             : #define LSTATE_INIT_ENCODE 0x02
      42             : /*
      43             :  * State block for each open TIFF
      44             :  * file using WEBP compression/decompression.
      45             :  */
      46             : typedef struct
      47             : {
      48             :     uint16_t nSamples; /* number of samples per pixel */
      49             : 
      50             :     int read_error; /* whether a read error has occurred, and which should cause
      51             :                        further reads in the same strip/tile to be aborted */
      52             :     int lossless;   /* lossy/lossless compression */
      53             :     int lossless_exact;   /* lossless exact mode. If TRUE, R,G,B values in areas
      54             :                              with alpha = 0 will be preserved */
      55             :     int quality_level;    /* compression level */
      56             :     WebPPicture sPicture; /* WebP Picture */
      57             :     WebPConfig sEncoderConfig;  /* WebP encoder config */
      58             :     uint8_t *pBuffer;           /* buffer to hold raw data on encoding */
      59             :     unsigned int buffer_offset; /* current offset into the buffer */
      60             :     unsigned int buffer_size;
      61             : 
      62             :     WebPIDecoder *psDecoder;  /* WebPIDecoder */
      63             :     WebPDecBuffer sDecBuffer; /* Decoder buffer */
      64             :     int last_y;               /* Last row decoded */
      65             : 
      66             :     int state; /* state flags */
      67             : 
      68             :     TIFFVGetMethod vgetparent; /* super-class method */
      69             :     TIFFVSetMethod vsetparent; /* super-class method */
      70             : } WebPState;
      71             : 
      72             : #define LState(tif) ((WebPState *)(tif)->tif_data)
      73             : #define DecoderState(tif) LState(tif)
      74             : #define EncoderState(tif) LState(tif)
      75             : 
      76             : static int TWebPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s);
      77             : static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s);
      78             : 
      79       16376 : static int TWebPDatasetWriter(const uint8_t *data, size_t data_size,
      80             :                               const WebPPicture *const picture)
      81             : {
      82             :     static const char module[] = "TWebPDatasetWriter";
      83       16376 :     TIFF *tif = (TIFF *)(picture->custom_ptr);
      84             : 
      85       16376 :     if ((tif->tif_rawcc + (tmsize_t)data_size) > tif->tif_rawdatasize)
      86             :     {
      87           0 :         TIFFErrorExtR(tif, module,
      88             :                       "Buffer too small by %" TIFF_SIZE_FORMAT " bytes.",
      89           0 :                       (size_t)((uint64_t)tif->tif_rawcc + (uint64_t)data_size -
      90           0 :                                (uint64_t)tif->tif_rawdatasize));
      91           0 :         return 0;
      92             :     }
      93             :     else
      94             :     {
      95       16376 :         _TIFFmemcpy(tif->tif_rawcp, data, (tmsize_t)data_size);
      96       16376 :         tif->tif_rawcc += (tmsize_t)data_size;
      97       16376 :         tif->tif_rawcp += data_size;
      98       16376 :         return 1;
      99             :     }
     100             : }
     101             : 
     102             : /*
     103             :  * Encode a chunk of pixels.
     104             :  */
     105        5016 : static int TWebPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
     106             : {
     107             :     static const char module[] = "TWebPEncode";
     108        5016 :     WebPState *sp = EncoderState(tif);
     109             :     (void)s;
     110             : 
     111        5016 :     assert(sp != NULL);
     112        5016 :     assert(sp->state == LSTATE_INIT_ENCODE);
     113             : 
     114        5016 :     if ((uint64_t)sp->buffer_offset + (uint64_t)cc > sp->buffer_size)
     115             :     {
     116           0 :         TIFFErrorExtR(tif, module, "Too many bytes to be written");
     117           0 :         return 0;
     118             :     }
     119             : 
     120        5016 :     memcpy(sp->pBuffer + sp->buffer_offset, bp, (size_t)cc);
     121        5016 :     sp->buffer_offset += (unsigned)cc;
     122             : 
     123        5016 :     return 1;
     124             : }
     125             : 
     126       15455 : static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
     127             : {
     128             :     static const char module[] = "WebPDecode";
     129       15455 :     VP8StatusCode status = VP8_STATUS_OK;
     130       15455 :     WebPState *sp = DecoderState(tif);
     131             :     uint32_t segment_width, segment_height;
     132       15455 :     bool decode_whole_strile = false;
     133             : 
     134             :     (void)s;
     135             : 
     136       15455 :     assert(sp != NULL);
     137       15455 :     assert(sp->state == LSTATE_INIT_DECODE);
     138             : 
     139       15455 :     if (sp->read_error)
     140             :     {
     141           0 :         memset(op, 0, (size_t)occ);
     142           0 :         TIFFErrorExtR(tif, module,
     143             :                       "ZIPDecode: Scanline %" PRIu32 " cannot be read due to "
     144             :                       "previous error",
     145             :                       tif->tif_dir.td_row);
     146           0 :         return 0;
     147             :     }
     148             : 
     149       15455 :     if (sp->psDecoder == NULL)
     150             :     {
     151        5515 :         TIFFDirectory *td = &tif->tif_dir;
     152             :         uint32_t buffer_size;
     153             : 
     154        5515 :         if (isTiled(tif))
     155             :         {
     156         851 :             segment_width = td->td_tilewidth;
     157         851 :             segment_height = td->td_tilelength;
     158             :         }
     159             :         else
     160             :         {
     161        4664 :             segment_width = td->td_imagewidth;
     162        4664 :             segment_height = td->td_imagelength - tif->tif_dir.td_row;
     163        4664 :             if (segment_height > td->td_rowsperstrip)
     164        4601 :                 segment_height = td->td_rowsperstrip;
     165             :         }
     166             : 
     167             :         int webp_width, webp_height;
     168        5515 :         if (!WebPGetInfo(tif->tif_rawcp,
     169        5515 :                          (uint64_t)tif->tif_rawcc > UINT32_MAX
     170             :                              ? UINT32_MAX
     171        5515 :                              : (uint32_t)tif->tif_rawcc,
     172             :                          &webp_width, &webp_height))
     173             :         {
     174           0 :             memset(op, 0, (size_t)occ);
     175           0 :             sp->read_error = 1;
     176           0 :             TIFFErrorExtR(tif, module, "WebPGetInfo() failed");
     177           0 :             return 0;
     178             :         }
     179        5515 :         if ((uint32_t)webp_width != segment_width ||
     180        5515 :             (uint32_t)webp_height != segment_height)
     181             :         {
     182           0 :             memset(op, 0, (size_t)occ);
     183           0 :             sp->read_error = 1;
     184           0 :             TIFFErrorExtR(
     185             :                 tif, module, "WebP blob dimension is %dx%d. Expected %ux%u",
     186             :                 webp_width, webp_height, segment_width, segment_height);
     187           0 :             return 0;
     188             :         }
     189             : 
     190             : #if WEBP_DECODER_ABI_VERSION >= 0x0002
     191             :         WebPDecoderConfig config;
     192        5515 :         if (!WebPInitDecoderConfig(&config))
     193             :         {
     194           0 :             memset(op, 0, (size_t)occ);
     195           0 :             sp->read_error = 1;
     196           0 :             TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
     197           0 :             return 0;
     198             :         }
     199             : 
     200        5515 :         const bool bWebPGetFeaturesOK =
     201        5515 :             WebPGetFeatures(tif->tif_rawcp,
     202        5515 :                             (uint64_t)tif->tif_rawcc > UINT32_MAX
     203             :                                 ? UINT32_MAX
     204        5515 :                                 : (uint32_t)tif->tif_rawcc,
     205             :                             &config.input) == VP8_STATUS_OK;
     206             : 
     207        5515 :         WebPFreeDecBuffer(&config.output);
     208             : 
     209        5515 :         if (!bWebPGetFeaturesOK)
     210             :         {
     211           0 :             memset(op, 0, (size_t)occ);
     212           0 :             sp->read_error = 1;
     213           0 :             TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
     214           0 :             return 0;
     215             :         }
     216             : 
     217        5515 :         const int webp_bands = config.input.has_alpha ? 4 : 3;
     218        5515 :         if (webp_bands != sp->nSamples &&
     219             :             /* We accept the situation where the WebP blob has only 3 bands,
     220             :              * whereas the raster is 4 bands. This can happen when the alpha
     221             :              * channel is fully opaque, and WebP decoding works fine in that
     222             :              * situation.
     223             :              */
     224           1 :             !(webp_bands == 3 && sp->nSamples == 4))
     225             :         {
     226           0 :             memset(op, 0, (size_t)occ);
     227           0 :             sp->read_error = 1;
     228           0 :             TIFFErrorExtR(tif, module,
     229             :                           "WebP blob band count is %d. Expected %d", webp_bands,
     230           0 :                           sp->nSamples);
     231           0 :             return 0;
     232             :         }
     233             : #endif
     234             : 
     235        5515 :         buffer_size = segment_width * segment_height * sp->nSamples;
     236        5515 :         if (occ == (tmsize_t)buffer_size)
     237             :         {
     238             :             /* If decoding the whole strip/tile, we can directly use the */
     239             :             /* output buffer */
     240        5510 :             decode_whole_strile = true;
     241             :         }
     242           5 :         else if (sp->pBuffer == NULL || buffer_size > sp->buffer_size)
     243             :         {
     244           3 :             if (sp->pBuffer != NULL)
     245             :             {
     246           0 :                 _TIFFfreeExt(tif, sp->pBuffer);
     247           0 :                 sp->pBuffer = NULL;
     248             :             }
     249             : 
     250           3 :             sp->pBuffer = (uint8_t *)_TIFFmallocExt(tif, buffer_size);
     251           3 :             if (!sp->pBuffer)
     252             :             {
     253           0 :                 TIFFErrorExtR(tif, module, "Cannot allocate buffer");
     254           0 :                 memset(op, 0, (size_t)occ);
     255           0 :                 sp->read_error = 1;
     256           0 :                 return 0;
     257             :             }
     258           3 :             sp->buffer_size = buffer_size;
     259             :         }
     260             : 
     261        5515 :         sp->last_y = 0;
     262             : 
     263        5515 :         WebPInitDecBuffer(&sp->sDecBuffer);
     264             : 
     265        5515 :         sp->sDecBuffer.is_external_memory = 1;
     266        5515 :         sp->sDecBuffer.width = (int)segment_width;
     267        5515 :         sp->sDecBuffer.height = (int)segment_height;
     268        5515 :         sp->sDecBuffer.u.RGBA.rgba = decode_whole_strile ? op : sp->pBuffer;
     269        5515 :         sp->sDecBuffer.u.RGBA.stride = (int)(segment_width * sp->nSamples);
     270        5515 :         sp->sDecBuffer.u.RGBA.size = buffer_size;
     271             : 
     272        5515 :         if (sp->nSamples > 3)
     273             :         {
     274           2 :             sp->sDecBuffer.colorspace = MODE_RGBA;
     275             :         }
     276             :         else
     277             :         {
     278        5513 :             sp->sDecBuffer.colorspace = MODE_RGB;
     279             :         }
     280             : 
     281        5515 :         sp->psDecoder = WebPINewDecoder(&sp->sDecBuffer);
     282             : 
     283        5515 :         if (sp->psDecoder == NULL)
     284             :         {
     285           0 :             memset(op, 0, (size_t)occ);
     286           0 :             sp->read_error = 1;
     287           0 :             TIFFErrorExtR(tif, module, "Unable to allocate WebP decoder.");
     288           0 :             return 0;
     289             :         }
     290             :     }
     291             : 
     292       15455 :     if (occ % sp->sDecBuffer.u.RGBA.stride)
     293             :     {
     294             :         // read_error not set here as this is a usage issue that can be
     295             :         // recovered in a following call.
     296           0 :         memset(op, 0, (size_t)occ);
     297             :         /* Do not set read_error as could potentially be recovered */
     298           0 :         TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
     299           0 :         return 0;
     300             :     }
     301             : 
     302       15455 :     status = WebPIAppend(sp->psDecoder, tif->tif_rawcp, (size_t)tif->tif_rawcc);
     303             : 
     304       15455 :     if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED)
     305             :     {
     306           0 :         if (status == VP8_STATUS_INVALID_PARAM)
     307             :         {
     308           0 :             TIFFErrorExtR(tif, module, "Invalid parameter used.");
     309             :         }
     310           0 :         else if (status == VP8_STATUS_OUT_OF_MEMORY)
     311             :         {
     312           0 :             TIFFErrorExtR(tif, module, "Out of memory.");
     313             :         }
     314             :         else
     315             :         {
     316           0 :             TIFFErrorExtR(tif, module, "Unrecognized error.");
     317             :         }
     318           0 :         memset(op, 0, (size_t)occ);
     319           0 :         sp->read_error = 1;
     320           0 :         return 0;
     321             :     }
     322             :     else
     323             :     {
     324             :         int current_y, stride;
     325             :         uint8_t *buf;
     326             : 
     327             :         /* Returns the RGB/A image decoded so far */
     328       15455 :         buf = WebPIDecGetRGB(sp->psDecoder, &current_y, NULL, NULL, &stride);
     329             : 
     330       15455 :         if ((buf != NULL) &&
     331       15455 :             (occ <= (tmsize_t)stride * (current_y - sp->last_y)))
     332             :         {
     333       15455 :             const int numberOfExpectedLines =
     334       15455 :                 (int)(occ / sp->sDecBuffer.u.RGBA.stride);
     335       15455 :             if (decode_whole_strile)
     336             :             {
     337        5510 :                 if (current_y != numberOfExpectedLines)
     338             :                 {
     339           0 :                     memset(op, 0, (size_t)occ);
     340           0 :                     sp->read_error = 1;
     341           0 :                     TIFFErrorExtR(tif, module,
     342             :                                   "Unable to decode WebP data: less lines than "
     343             :                                   "expected.");
     344           0 :                     return 0;
     345             :                 }
     346             :             }
     347             :             else
     348             :             {
     349        9945 :                 memcpy(op, buf + (sp->last_y * stride), (size_t)occ);
     350             :             }
     351             : 
     352       15455 :             tif->tif_rawcp += tif->tif_rawcc;
     353       15455 :             tif->tif_rawcc = 0;
     354       15455 :             sp->last_y += numberOfExpectedLines;
     355             : 
     356       15455 :             if (decode_whole_strile)
     357             :             {
     358             :                 /* We can now free the decoder as we're completely done */
     359        5510 :                 if (sp->psDecoder != NULL)
     360             :                 {
     361        5510 :                     WebPIDelete(sp->psDecoder);
     362        5510 :                     WebPFreeDecBuffer(&sp->sDecBuffer);
     363        5510 :                     sp->psDecoder = NULL;
     364             :                 }
     365             :             }
     366       15455 :             return 1;
     367             :         }
     368             :         else
     369             :         {
     370           0 :             memset(op, 0, (size_t)occ);
     371           0 :             sp->read_error = 1;
     372           0 :             TIFFErrorExtR(tif, module, "Unable to decode WebP data.");
     373           0 :             return 0;
     374             :         }
     375             :     }
     376             : }
     377             : 
     378         406 : static int TWebPFixupTags(TIFF *tif)
     379             : {
     380             :     (void)tif;
     381         406 :     if (tif->tif_dir.td_planarconfig != PLANARCONFIG_CONTIG)
     382             :     {
     383             :         static const char module[] = "TWebPFixupTags";
     384           0 :         TIFFErrorExtR(tif, module,
     385             :                       "TIFF WEBP requires data to be stored contiguously in "
     386             :                       "RGB e.g. RGBRGBRGB "
     387             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     388             :                       "or RGBARGBARGBA"
     389             : #endif
     390             :         );
     391           0 :         return 0;
     392             :     }
     393         406 :     return 1;
     394             : }
     395             : 
     396          97 : static int TWebPSetupDecode(TIFF *tif)
     397             : {
     398             :     static const char module[] = "WebPSetupDecode";
     399          97 :     uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample;
     400          97 :     uint16_t sampleFormat = tif->tif_dir.td_sampleformat;
     401             : 
     402          97 :     WebPState *sp = DecoderState(tif);
     403          97 :     assert(sp != NULL);
     404             : 
     405          97 :     sp->nSamples = tif->tif_dir.td_samplesperpixel;
     406             : 
     407             :     /* check band count */
     408          97 :     if (sp->nSamples != 3
     409             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     410           2 :         && sp->nSamples != 4
     411             : #endif
     412             :     )
     413             :     {
     414           0 :         TIFFErrorExtR(tif, module,
     415             :                       "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
     416             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     417             :                       "or 4 (RGBA) "
     418             : #endif
     419             :                       "bands.",
     420           0 :                       sp->nSamples);
     421           0 :         return 0;
     422             :     }
     423             : 
     424             :     /* check bits per sample and data type */
     425          97 :     if ((nBitsPerSample != 8) && (sampleFormat != 1))
     426             :     {
     427           0 :         TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data");
     428           0 :         return 0;
     429             :     }
     430             : 
     431             :     /* if we were last encoding, terminate this mode */
     432          97 :     if (sp->state & LSTATE_INIT_ENCODE)
     433             :     {
     434           9 :         WebPPictureFree(&sp->sPicture);
     435           9 :         if (sp->pBuffer != NULL)
     436             :         {
     437           9 :             _TIFFfreeExt(tif, sp->pBuffer);
     438           9 :             sp->pBuffer = NULL;
     439             :         }
     440           9 :         sp->buffer_offset = 0;
     441           9 :         sp->state = 0;
     442             :     }
     443             : 
     444          97 :     sp->state |= LSTATE_INIT_DECODE;
     445             : 
     446          97 :     return 1;
     447             : }
     448             : 
     449             : /*
     450             :  * Setup state for decoding a strip.
     451             :  */
     452        5515 : static int TWebPPreDecode(TIFF *tif, uint16_t s)
     453             : {
     454             :     static const char module[] = "TWebPPreDecode";
     455             :     uint32_t segment_width, segment_height;
     456        5515 :     WebPState *sp = DecoderState(tif);
     457        5515 :     TIFFDirectory *td = &tif->tif_dir;
     458             :     (void)s;
     459        5515 :     assert(sp != NULL);
     460             : 
     461        5515 :     if (isTiled(tif))
     462             :     {
     463         851 :         segment_width = td->td_tilewidth;
     464         851 :         segment_height = td->td_tilelength;
     465             :     }
     466             :     else
     467             :     {
     468        4664 :         segment_width = td->td_imagewidth;
     469        4664 :         segment_height = td->td_imagelength - tif->tif_dir.td_row;
     470        4664 :         if (segment_height > td->td_rowsperstrip)
     471        4601 :             segment_height = td->td_rowsperstrip;
     472             :     }
     473             : 
     474        5515 :     if (segment_width > 16383 || segment_height > 16383)
     475             :     {
     476           0 :         TIFFErrorExtR(tif, module,
     477             :                       "WEBP maximum image dimensions are 16383 x 16383.");
     478           0 :         return 0;
     479             :     }
     480             : 
     481        5515 :     if ((sp->state & LSTATE_INIT_DECODE) == 0)
     482           9 :         tif->tif_setupdecode(tif);
     483             : 
     484        5515 :     if (sp->psDecoder != NULL)
     485             :     {
     486           2 :         WebPIDelete(sp->psDecoder);
     487           2 :         WebPFreeDecBuffer(&sp->sDecBuffer);
     488           2 :         sp->psDecoder = NULL;
     489             :     }
     490             : 
     491        5515 :     sp->read_error = 0;
     492             : 
     493        5515 :     return 1;
     494             : }
     495             : 
     496          64 : static int TWebPSetupEncode(TIFF *tif)
     497             : {
     498             :     static const char module[] = "WebPSetupEncode";
     499          64 :     uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample;
     500          64 :     uint16_t sampleFormat = tif->tif_dir.td_sampleformat;
     501             : 
     502          64 :     WebPState *sp = EncoderState(tif);
     503          64 :     assert(sp != NULL);
     504             : 
     505          64 :     sp->nSamples = tif->tif_dir.td_samplesperpixel;
     506             : 
     507             :     /* check band count */
     508          64 :     if (sp->nSamples != 3
     509             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     510           1 :         && sp->nSamples != 4
     511             : #endif
     512             :     )
     513             :     {
     514           0 :         TIFFErrorExtR(tif, module,
     515             :                       "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
     516             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     517             :                       "or 4 (RGBA) "
     518             : #endif
     519             :                       "bands.",
     520           0 :                       sp->nSamples);
     521           0 :         return 0;
     522             :     }
     523             : 
     524             :     /* check bits per sample and data type */
     525          64 :     if ((nBitsPerSample != 8) || (sampleFormat != SAMPLEFORMAT_UINT))
     526             :     {
     527           0 :         TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data");
     528           0 :         return 0;
     529             :     }
     530             : 
     531          64 :     if (sp->state & LSTATE_INIT_DECODE)
     532             :     {
     533           0 :         WebPIDelete(sp->psDecoder);
     534           0 :         WebPFreeDecBuffer(&sp->sDecBuffer);
     535           0 :         sp->psDecoder = NULL;
     536           0 :         sp->last_y = 0;
     537           0 :         sp->state = 0;
     538             :     }
     539             : 
     540          64 :     sp->state |= LSTATE_INIT_ENCODE;
     541             : 
     542          64 :     if (!WebPPictureInit(&sp->sPicture))
     543             :     {
     544           0 :         TIFFErrorExtR(tif, module, "Error initializing WebP picture.");
     545           0 :         return 0;
     546             :     }
     547             : 
     548          64 :     if (!WebPConfigInitInternal(&sp->sEncoderConfig, WEBP_PRESET_DEFAULT,
     549          64 :                                 (float)sp->quality_level,
     550             :                                 WEBP_ENCODER_ABI_VERSION))
     551             :     {
     552           0 :         TIFFErrorExtR(tif, module,
     553             :                       "Error creating WebP encoder configuration.");
     554           0 :         return 0;
     555             :     }
     556             : 
     557             : // WebPConfigInitInternal above sets lossless to false
     558             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     559          64 :     sp->sEncoderConfig.lossless = sp->lossless;
     560          64 :     if (sp->lossless)
     561             :     {
     562          15 :         sp->sPicture.use_argb = 1;
     563             : #if WEBP_ENCODER_ABI_VERSION >= 0x0209
     564          15 :         sp->sEncoderConfig.exact = sp->lossless_exact;
     565             : #endif
     566             :     }
     567             : #endif
     568             : 
     569          64 :     if (!WebPValidateConfig(&sp->sEncoderConfig))
     570             :     {
     571           0 :         TIFFErrorExtR(tif, module, "Error with WebP encoder configuration.");
     572           0 :         return 0;
     573             :     }
     574             : 
     575          64 :     return 1;
     576             : }
     577             : 
     578             : /*
     579             :  * Reset encoding state at the start of a strip.
     580             :  */
     581        3016 : static int TWebPPreEncode(TIFF *tif, uint16_t s)
     582             : {
     583             :     static const char module[] = "TWebPPreEncode";
     584             :     uint32_t segment_width, segment_height;
     585        3016 :     WebPState *sp = EncoderState(tif);
     586        3016 :     TIFFDirectory *td = &tif->tif_dir;
     587             : 
     588             :     (void)s;
     589             : 
     590        3016 :     assert(sp != NULL);
     591        3016 :     if (sp->state != LSTATE_INIT_ENCODE)
     592           0 :         tif->tif_setupencode(tif);
     593             : 
     594             :     /*
     595             :      * Set encoding parameters for this strip/tile.
     596             :      */
     597        3016 :     if (isTiled(tif))
     598             :     {
     599         426 :         segment_width = td->td_tilewidth;
     600         426 :         segment_height = td->td_tilelength;
     601             :     }
     602             :     else
     603             :     {
     604        2590 :         segment_width = td->td_imagewidth;
     605        2590 :         segment_height = td->td_imagelength - tif->tif_dir.td_row;
     606        2590 :         if (segment_height > td->td_rowsperstrip)
     607        2553 :             segment_height = td->td_rowsperstrip;
     608             :     }
     609             : 
     610        3016 :     if (segment_width > 16383 || segment_height > 16383)
     611             :     {
     612           0 :         TIFFErrorExtR(tif, module,
     613             :                       "WEBP maximum image dimensions are 16383 x 16383.");
     614           0 :         return 0;
     615             :     }
     616             : 
     617             :     /* set up buffer for raw data */
     618             :     /* given above check and that nSamples <= 4, buffer_size is <= 1 GB */
     619        3016 :     sp->buffer_size = segment_width * segment_height * sp->nSamples;
     620             : 
     621        3016 :     if (sp->pBuffer != NULL)
     622             :     {
     623        2952 :         _TIFFfreeExt(tif, sp->pBuffer);
     624        2952 :         sp->pBuffer = NULL;
     625             :     }
     626             : 
     627        3016 :     sp->pBuffer = (uint8_t *)_TIFFmallocExt(tif, sp->buffer_size);
     628        3016 :     if (!sp->pBuffer)
     629             :     {
     630           0 :         TIFFErrorExtR(tif, module, "Cannot allocate buffer");
     631           0 :         return 0;
     632             :     }
     633        3016 :     sp->buffer_offset = 0;
     634             : 
     635        3016 :     sp->sPicture.width = (int)segment_width;
     636        3016 :     sp->sPicture.height = (int)segment_height;
     637        3016 :     sp->sPicture.writer = TWebPDatasetWriter;
     638        3016 :     sp->sPicture.custom_ptr = tif;
     639             : 
     640        3016 :     return 1;
     641             : }
     642             : 
     643             : /*
     644             :  * Finish off an encoded strip by flushing it.
     645             :  */
     646        3016 : static int TWebPPostEncode(TIFF *tif)
     647             : {
     648             :     static const char module[] = "WebPPostEncode";
     649             :     int64_t stride;
     650        3016 :     WebPState *sp = EncoderState(tif);
     651        3016 :     assert(sp != NULL);
     652             : 
     653        3016 :     assert(sp->state == LSTATE_INIT_ENCODE);
     654             : 
     655        3016 :     stride = (int64_t)sp->sPicture.width * sp->nSamples;
     656             : 
     657             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     658        3016 :     if (sp->nSamples == 4)
     659             :     {
     660           1 :         if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride))
     661             :         {
     662           0 :             TIFFErrorExtR(tif, module, "WebPPictureImportRGBA() failed");
     663           0 :             return 0;
     664             :         }
     665             :     }
     666             :     else
     667             : #endif
     668        3015 :         if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride))
     669             :     {
     670           0 :         TIFFErrorExtR(tif, module, "WebPPictureImportRGB() failed");
     671           0 :         return 0;
     672             :     }
     673             : 
     674        3016 :     if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture))
     675             :     {
     676             : 
     677             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     678           0 :         const char *pszErrorMsg = NULL;
     679           0 :         switch (sp->sPicture.error_code)
     680             :         {
     681           0 :             case VP8_ENC_ERROR_OUT_OF_MEMORY:
     682           0 :                 pszErrorMsg = "Out of memory";
     683           0 :                 break;
     684           0 :             case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
     685           0 :                 pszErrorMsg = "Out of memory while flushing bits";
     686           0 :                 break;
     687           0 :             case VP8_ENC_ERROR_NULL_PARAMETER:
     688           0 :                 pszErrorMsg = "A pointer parameter is NULL";
     689           0 :                 break;
     690           0 :             case VP8_ENC_ERROR_INVALID_CONFIGURATION:
     691           0 :                 pszErrorMsg = "Configuration is invalid";
     692           0 :                 break;
     693           0 :             case VP8_ENC_ERROR_BAD_DIMENSION:
     694           0 :                 pszErrorMsg = "Picture has invalid width/height";
     695           0 :                 break;
     696           0 :             case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
     697           0 :                 pszErrorMsg = "Partition is bigger than 512k. Try using less "
     698             :                               "SEGMENTS, or increase PARTITION_LIMIT value";
     699           0 :                 break;
     700           0 :             case VP8_ENC_ERROR_PARTITION_OVERFLOW:
     701           0 :                 pszErrorMsg = "Partition is bigger than 16M";
     702           0 :                 break;
     703           0 :             case VP8_ENC_ERROR_BAD_WRITE:
     704           0 :                 pszErrorMsg = "Error while fludshing bytes";
     705           0 :                 break;
     706           0 :             case VP8_ENC_ERROR_FILE_TOO_BIG:
     707           0 :                 pszErrorMsg = "File is bigger than 4G";
     708           0 :                 break;
     709           0 :             case VP8_ENC_ERROR_USER_ABORT:
     710           0 :                 pszErrorMsg = "User interrupted";
     711           0 :                 break;
     712           0 :             case VP8_ENC_OK:
     713             :             case VP8_ENC_ERROR_LAST:
     714             :             default:
     715           0 :                 TIFFErrorExtR(tif, module,
     716             :                               "WebPEncode returned an unknown error code: %u",
     717           0 :                               sp->sPicture.error_code);
     718           0 :                 pszErrorMsg = "Unknown WebP error type.";
     719           0 :                 break;
     720             :         }
     721           0 :         TIFFErrorExtR(tif, module, "WebPEncode() failed : %s", pszErrorMsg);
     722             : #else
     723             :         TIFFErrorExtR(tif, module, "Error in WebPEncode()");
     724             : #endif
     725           0 :         return 0;
     726             :     }
     727             : 
     728        3016 :     sp->sPicture.custom_ptr = NULL;
     729             : 
     730        3016 :     if (!TIFFFlushData1(tif))
     731             :     {
     732           0 :         TIFFErrorExtR(tif, module, "Error flushing TIFF WebP encoder.");
     733           0 :         return 0;
     734             :     }
     735             : 
     736        3016 :     return 1;
     737             : }
     738             : 
     739         509 : static void TWebPCleanup(TIFF *tif)
     740             : {
     741         509 :     WebPState *sp = LState(tif);
     742             : 
     743         509 :     assert(sp != 0);
     744             : 
     745         509 :     tif->tif_tagmethods.vgetfield = sp->vgetparent;
     746         509 :     tif->tif_tagmethods.vsetfield = sp->vsetparent;
     747             : 
     748         509 :     if (sp->state & LSTATE_INIT_ENCODE)
     749             :     {
     750          55 :         WebPPictureFree(&sp->sPicture);
     751             :     }
     752             : 
     753         509 :     if (sp->psDecoder != NULL)
     754             :     {
     755           3 :         WebPIDelete(sp->psDecoder);
     756           3 :         WebPFreeDecBuffer(&sp->sDecBuffer);
     757           3 :         sp->psDecoder = NULL;
     758           3 :         sp->last_y = 0;
     759             :     }
     760             : 
     761         509 :     if (sp->pBuffer != NULL)
     762             :     {
     763          58 :         _TIFFfreeExt(tif, sp->pBuffer);
     764          58 :         sp->pBuffer = NULL;
     765             :     }
     766             : 
     767         509 :     _TIFFfreeExt(tif, tif->tif_data);
     768         509 :     tif->tif_data = NULL;
     769             : 
     770         509 :     _TIFFSetDefaultCompressionState(tif);
     771         509 : }
     772             : 
     773        4661 : static int TWebPVSetField(TIFF *tif, uint32_t tag, va_list ap)
     774             : {
     775             :     static const char module[] = "WebPVSetField";
     776        4661 :     WebPState *sp = LState(tif);
     777             : 
     778        4661 :     switch (tag)
     779             :     {
     780         174 :         case TIFFTAG_WEBP_LEVEL:
     781         174 :             sp->quality_level = (int)va_arg(ap, int);
     782         174 :             if (sp->quality_level <= 0 || sp->quality_level > 100)
     783             :             {
     784           0 :                 TIFFWarningExtR(tif, module,
     785             :                                 "WEBP_LEVEL should be between 1 and 100");
     786             :             }
     787         174 :             return 1;
     788          63 :         case TIFFTAG_WEBP_LOSSLESS:
     789             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
     790          63 :             sp->lossless = va_arg(ap, int);
     791          63 :             if (sp->lossless)
     792             :             {
     793          63 :                 sp->quality_level = 100;
     794             :             }
     795          63 :             return 1;
     796             : #else
     797             :             TIFFErrorExtR(
     798             :                 tif, module,
     799             :                 "Need to upgrade WEBP driver, this version doesn't support "
     800             :                 "lossless compression.");
     801             :             return 0;
     802             : #endif
     803           0 :         case TIFFTAG_WEBP_LOSSLESS_EXACT:
     804             : #if WEBP_ENCODER_ABI_VERSION >= 0x0209
     805           0 :             sp->lossless_exact = va_arg(ap, int);
     806           0 :             return 1;
     807             : #else
     808             :             TIFFErrorExtR(
     809             :                 tif, module,
     810             :                 "Need to upgrade WEBP driver, this version doesn't support "
     811             :                 "lossless compression.");
     812             :             return 0;
     813             : #endif
     814        4424 :         default:
     815        4424 :             return (*sp->vsetparent)(tif, tag, ap);
     816             :     }
     817             :     /*NOTREACHED*/
     818             : }
     819             : 
     820       17187 : static int TWebPVGetField(TIFF *tif, uint32_t tag, va_list ap)
     821             : {
     822       17187 :     WebPState *sp = LState(tif);
     823             : 
     824       17187 :     switch (tag)
     825             :     {
     826           0 :         case TIFFTAG_WEBP_LEVEL:
     827           0 :             *va_arg(ap, int *) = sp->quality_level;
     828           0 :             break;
     829           0 :         case TIFFTAG_WEBP_LOSSLESS:
     830           0 :             *va_arg(ap, int *) = sp->lossless;
     831           0 :             break;
     832           0 :         case TIFFTAG_WEBP_LOSSLESS_EXACT:
     833           0 :             *va_arg(ap, int *) = sp->lossless_exact;
     834           0 :             break;
     835       17187 :         default:
     836       17187 :             return (*sp->vgetparent)(tif, tag, ap);
     837             :     }
     838           0 :     return 1;
     839             : }
     840             : 
     841             : static const TIFFField TWebPFields[] = {
     842             :     {TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO, TRUE,
     843             :      FALSE, "WEBP quality", NULL},
     844             :     {TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, FIELD_PSEUDO,
     845             :      TRUE, FALSE, "WEBP lossless/lossy", NULL},
     846             :     {TIFFTAG_WEBP_LOSSLESS_EXACT, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
     847             :      FIELD_PSEUDO, TRUE, FALSE, "WEBP exact lossless", NULL},
     848             : };
     849             : 
     850         509 : int TIFFInitWebP(TIFF *tif, int scheme)
     851             : {
     852             :     static const char module[] = "TIFFInitWebP";
     853             :     WebPState *sp;
     854             : 
     855             :     (void)scheme;
     856         509 :     assert(scheme == COMPRESSION_WEBP);
     857             : 
     858             :     /*
     859             :      * Merge codec-specific tag information.
     860             :      */
     861         509 :     if (!_TIFFMergeFields(tif, TWebPFields, TIFFArrayCount(TWebPFields)))
     862             :     {
     863           0 :         TIFFErrorExtR(tif, module, "Merging WebP codec-specific tags failed");
     864           0 :         return 0;
     865             :     }
     866             : 
     867             :     /*
     868             :      * Allocate state block so tag methods have storage to record values.
     869             :      */
     870         509 :     tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(WebPState));
     871         509 :     if (tif->tif_data == NULL)
     872           0 :         goto bad;
     873         509 :     sp = LState(tif);
     874             : 
     875             :     /*
     876             :      * Override parent get/set field methods.
     877             :      */
     878         509 :     sp->vgetparent = tif->tif_tagmethods.vgetfield;
     879         509 :     tif->tif_tagmethods.vgetfield = TWebPVGetField; /* hook for codec tags */
     880         509 :     sp->vsetparent = tif->tif_tagmethods.vsetfield;
     881         509 :     tif->tif_tagmethods.vsetfield = TWebPVSetField; /* hook for codec tags */
     882             : 
     883             :     /* Default values for codec-specific fields */
     884         509 :     sp->quality_level = 75; /* default comp. level */
     885         509 :     sp->lossless = 0;       /* default to false */
     886         509 :     sp->lossless_exact = 1; /* exact lossless mode (if lossless enabled) */
     887         509 :     sp->state = 0;
     888         509 :     sp->nSamples = 0;
     889         509 :     sp->psDecoder = NULL;
     890         509 :     sp->last_y = 0;
     891             : 
     892         509 :     sp->buffer_offset = 0;
     893         509 :     sp->pBuffer = NULL;
     894             : 
     895             :     /*
     896             :      * Install codec methods.
     897             :      * Notes:
     898             :      * encoderow is not supported
     899             :      */
     900         509 :     tif->tif_fixuptags = TWebPFixupTags;
     901         509 :     tif->tif_setupdecode = TWebPSetupDecode;
     902         509 :     tif->tif_predecode = TWebPPreDecode;
     903         509 :     tif->tif_decoderow = TWebPDecode;
     904         509 :     tif->tif_decodestrip = TWebPDecode;
     905         509 :     tif->tif_decodetile = TWebPDecode;
     906         509 :     tif->tif_setupencode = TWebPSetupEncode;
     907         509 :     tif->tif_preencode = TWebPPreEncode;
     908         509 :     tif->tif_postencode = TWebPPostEncode;
     909         509 :     tif->tif_encoderow = TWebPEncode;
     910         509 :     tif->tif_encodestrip = TWebPEncode;
     911         509 :     tif->tif_encodetile = TWebPEncode;
     912         509 :     tif->tif_cleanup = TWebPCleanup;
     913             : 
     914         509 :     return 1;
     915           0 : bad:
     916           0 :     TIFFErrorExtR(tif, module, "No space for WebP state block");
     917           0 :     return 0;
     918             : }
     919             : 
     920             : #endif /* WEBP_SUPPORT */

Generated by: LCOV version 1.14