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

Generated by: LCOV version 1.14