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

Generated by: LCOV version 1.14