xref: /reactos/dll/3rdparty/libtiff/tif_webp.c (revision f87faf67)
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 <stdio.h>
38 
39 #define LSTATE_INIT_DECODE 0x01
40 #define LSTATE_INIT_ENCODE 0x02
41 /*
42  * State block for each open TIFF
43  * file using WEBP compression/decompression.
44  */
45 typedef struct {
46   uint16           nSamples;               /* number of samples per pixel */
47 
48   int              lossless;               /* lossy/lossless compression */
49   int              quality_level;          /* compression level */
50   WebPPicture      sPicture;               /* WebP Picture */
51   WebPConfig       sEncoderConfig;         /* WebP encoder config */
52   uint8*           pBuffer;                /* buffer to hold raw data on encoding */
53   unsigned int     buffer_offset;          /* current offset into the buffer */
54   unsigned int     buffer_size;
55 
56   WebPIDecoder*    psDecoder;              /* WebPIDecoder */
57   WebPDecBuffer    sDecBuffer;             /* Decoder buffer */
58   int              last_y;                 /* Last row decoded */
59 
60   int              state;                  /* state flags */
61 
62 	TIFFVGetMethod   vgetparent;             /* super-class method */
63 	TIFFVSetMethod   vsetparent;             /* super-class method */
64 } WebPState;
65 
66 #define LState(tif)            ((WebPState*) (tif)->tif_data)
67 #define DecoderState(tif)       LState(tif)
68 #define EncoderState(tif)       LState(tif)
69 
70 static int TWebPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
71 static int TWebPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
72 
73 static
TWebPDatasetWriter(const uint8_t * data,size_t data_size,const WebPPicture * const picture)74 int TWebPDatasetWriter(const uint8_t* data, size_t data_size,
75                       const WebPPicture* const picture)
76 {
77   static const char module[] = "TWebPDatasetWriter";
78   TIFF* tif = (TIFF*)(picture->custom_ptr);
79 
80   if ( (tif->tif_rawcc + (tmsize_t)data_size) > tif->tif_rawdatasize ) {
81     TIFFErrorExt(tif->tif_clientdata, module,
82                  "Buffer too small by " TIFF_SIZE_FORMAT " bytes.",
83                  (size_t) (tif->tif_rawcc + data_size - tif->tif_rawdatasize));
84     return 0;
85   } else {
86     _TIFFmemcpy(tif->tif_rawcp, data, data_size);
87     tif->tif_rawcc += data_size;
88     tif->tif_rawcp += data_size;
89     return 1;
90   }
91 }
92 
93 /*
94  * Encode a chunk of pixels.
95  */
96 static int
TWebPEncode(TIFF * tif,uint8 * bp,tmsize_t cc,uint16 s)97 TWebPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
98 {
99   static const char module[] = "TWebPEncode";
100   WebPState *sp = EncoderState(tif);
101   (void) s;
102 
103   assert(sp != NULL);
104   assert(sp->state == LSTATE_INIT_ENCODE);
105 
106   if( (uint64)sp->buffer_offset +
107                             (uint64)cc > sp->buffer_size )
108   {
109       TIFFErrorExt(tif->tif_clientdata, module,
110                    "Too many bytes to be written");
111       return 0;
112   }
113 
114   memcpy(sp->pBuffer + sp->buffer_offset,
115          bp, cc);
116   sp->buffer_offset += (unsigned)cc;
117 
118   return 1;
119 
120 }
121 
122 static int
TWebPDecode(TIFF * tif,uint8 * op,tmsize_t occ,uint16 s)123 TWebPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
124 {
125   static const char module[] = "WebPDecode";
126   VP8StatusCode status = VP8_STATUS_OK;
127   WebPState *sp = DecoderState(tif);
128   (void) s;
129 
130   assert(sp != NULL);
131   assert(sp->state == LSTATE_INIT_DECODE);
132 
133   if (occ % sp->sDecBuffer.u.RGBA.stride)
134   {
135     TIFFErrorExt(tif->tif_clientdata, module,
136                  "Fractional scanlines cannot be read");
137     return 0;
138   }
139 
140   status = WebPIAppend(sp->psDecoder, tif->tif_rawcp, tif->tif_rawcc);
141 
142   if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
143     if (status == VP8_STATUS_INVALID_PARAM) {
144        TIFFErrorExt(tif->tif_clientdata, module,
145          "Invalid parameter used.");
146     } else if (status == VP8_STATUS_OUT_OF_MEMORY) {
147       TIFFErrorExt(tif->tif_clientdata, module,
148         "Out of memory.");
149     } else {
150       TIFFErrorExt(tif->tif_clientdata, module,
151         "Unrecognized error.");
152     }
153     return 0;
154   } else {
155     int current_y, stride;
156     uint8_t* buf;
157 
158     /* Returns the RGB/A image decoded so far */
159     buf = WebPIDecGetRGB(sp->psDecoder, &current_y, NULL, NULL, &stride);
160 
161     if ((buf != NULL) &&
162         (occ <= stride * (current_y - sp->last_y))) {
163       memcpy(op,
164          buf + (sp->last_y * stride),
165          occ);
166 
167       tif->tif_rawcp += tif->tif_rawcc;
168       tif->tif_rawcc = 0;
169       sp->last_y += occ / sp->sDecBuffer.u.RGBA.stride;
170       return 1;
171     } else {
172       TIFFErrorExt(tif->tif_clientdata, module, "Unable to decode WebP data.");
173       return 0;
174     }
175   }
176 }
177 
178 static int
TWebPFixupTags(TIFF * tif)179 TWebPFixupTags(TIFF* tif)
180 {
181   (void) tif;
182   if (tif->tif_dir.td_planarconfig != PLANARCONFIG_CONTIG) {
183     static const char module[] = "TWebPFixupTags";
184     TIFFErrorExt(tif->tif_clientdata, module,
185       "TIFF WEBP requires data to be stored contiguously in RGB e.g. RGBRGBRGB "
186 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
187       "or RGBARGBARGBA"
188 #endif
189     );
190     return 0;
191   }
192   return 1;
193 }
194 
195 static int
TWebPSetupDecode(TIFF * tif)196 TWebPSetupDecode(TIFF* tif)
197 {
198   static const char module[] = "WebPSetupDecode";
199   uint16 nBitsPerSample = tif->tif_dir.td_bitspersample;
200   uint16 sampleFormat = tif->tif_dir.td_sampleformat;
201 
202   WebPState* sp = DecoderState(tif);
203   assert(sp != NULL);
204 
205   sp->nSamples = tif->tif_dir.td_samplesperpixel;
206 
207   /* check band count */
208   if ( sp->nSamples != 3
209 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
210     && sp->nSamples != 4
211 #endif
212   )
213   {
214     TIFFErrorExt(tif->tif_clientdata, module,
215       "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
216   #if WEBP_ENCODER_ABI_VERSION >= 0x0100
217       "or 4 (RGBA) "
218   #endif
219     "bands.",
220     sp->nSamples );
221     return 0;
222   }
223 
224   /* check bits per sample and data type */
225   if ((nBitsPerSample != 8) && (sampleFormat != 1)) {
226     TIFFErrorExt(tif->tif_clientdata, module,
227                 "WEBP driver requires 8 bit unsigned data");
228     return 0;
229   }
230 
231   /* if we were last encoding, terminate this mode */
232   if (sp->state & LSTATE_INIT_ENCODE) {
233       WebPPictureFree(&sp->sPicture);
234       if (sp->pBuffer != NULL) {
235         _TIFFfree(sp->pBuffer);
236         sp->pBuffer = NULL;
237       }
238       sp->buffer_offset = 0;
239       sp->state = 0;
240   }
241 
242   sp->state |= LSTATE_INIT_DECODE;
243 
244   return 1;
245 }
246 
247 /*
248 * Setup state for decoding a strip.
249 */
250 static int
TWebPPreDecode(TIFF * tif,uint16 s)251 TWebPPreDecode(TIFF* tif, uint16 s)
252 {
253   static const char module[] = "TWebPPreDecode";
254   uint32 segment_width, segment_height;
255   WebPState* sp = DecoderState(tif);
256   TIFFDirectory* td = &tif->tif_dir;
257   (void) s;
258   assert(sp != NULL);
259 
260   if (isTiled(tif)) {
261     segment_width = td->td_tilewidth;
262     segment_height = td->td_tilelength;
263   } else {
264     segment_width = td->td_imagewidth;
265     segment_height = td->td_imagelength - tif->tif_row;
266     if (segment_height > td->td_rowsperstrip)
267       segment_height = td->td_rowsperstrip;
268   }
269 
270   if( (sp->state & LSTATE_INIT_DECODE) == 0 )
271       tif->tif_setupdecode(tif);
272 
273   if (sp->psDecoder != NULL) {
274     WebPIDelete(sp->psDecoder);
275     WebPFreeDecBuffer(&sp->sDecBuffer);
276     sp->psDecoder = NULL;
277   }
278 
279   sp->last_y = 0;
280 
281   WebPInitDecBuffer(&sp->sDecBuffer);
282 
283   sp->sDecBuffer.is_external_memory = 0;
284   sp->sDecBuffer.width = segment_width;
285   sp->sDecBuffer.height = segment_height;
286   sp->sDecBuffer.u.RGBA.stride = segment_width * sp->nSamples;
287   sp->sDecBuffer.u.RGBA.size = segment_width * sp->nSamples * segment_height;
288 
289   if (sp->nSamples > 3) {
290     sp->sDecBuffer.colorspace = MODE_RGBA;
291   } else {
292     sp->sDecBuffer.colorspace = MODE_RGB;
293   }
294 
295   sp->psDecoder = WebPINewDecoder(&sp->sDecBuffer);
296 
297   if (sp->psDecoder == NULL) {
298     TIFFErrorExt(tif->tif_clientdata, module,
299                 "Unable to allocate WebP decoder.");
300     return 0;
301   }
302 
303   return 1;
304 }
305 
306 static int
TWebPSetupEncode(TIFF * tif)307 TWebPSetupEncode(TIFF* tif)
308 {
309   static const char module[] = "WebPSetupEncode";
310   uint16 nBitsPerSample = tif->tif_dir.td_bitspersample;
311   uint16 sampleFormat = tif->tif_dir.td_sampleformat;
312 
313   WebPState* sp = EncoderState(tif);
314   assert(sp != NULL);
315 
316   sp->nSamples = tif->tif_dir.td_samplesperpixel;
317 
318   /* check band count */
319   if ( sp->nSamples != 3
320 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
321     && sp->nSamples != 4
322 #endif
323   )
324   {
325     TIFFErrorExt(tif->tif_clientdata, module,
326       "WEBP driver doesn't support %d bands. Must be 3 (RGB) "
327 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
328       "or 4 (RGBA) "
329 #endif
330     "bands.",
331     sp->nSamples );
332     return 0;
333   }
334 
335   /* check bits per sample and data type */
336   if ((nBitsPerSample != 8) && (sampleFormat != 1)) {
337     TIFFErrorExt(tif->tif_clientdata, module,
338                 "WEBP driver requires 8 bit unsigned data");
339     return 0;
340   }
341 
342   if (sp->state & LSTATE_INIT_DECODE) {
343     WebPIDelete(sp->psDecoder);
344     WebPFreeDecBuffer(&sp->sDecBuffer);
345     sp->psDecoder = NULL;
346     sp->last_y = 0;
347     sp->state = 0;
348   }
349 
350   sp->state |= LSTATE_INIT_ENCODE;
351 
352   if (!WebPPictureInit(&sp->sPicture)) {
353     TIFFErrorExt(tif->tif_clientdata, module,
354         "Error initializing WebP picture.");
355     return 0;
356   }
357 
358   if (!WebPConfigInitInternal(&sp->sEncoderConfig, WEBP_PRESET_DEFAULT,
359                               sp->quality_level,
360                               WEBP_ENCODER_ABI_VERSION)) {
361     TIFFErrorExt(tif->tif_clientdata, module,
362       "Error creating WebP encoder configuration.");
363     return 0;
364   }
365 
366   // WebPConfigInitInternal above sets lossless to false
367   #if WEBP_ENCODER_ABI_VERSION >= 0x0100
368     sp->sEncoderConfig.lossless = sp->lossless;
369     if (sp->lossless) {
370       sp->sPicture.use_argb = 1;
371     }
372   #endif
373 
374   if (!WebPValidateConfig(&sp->sEncoderConfig)) {
375     TIFFErrorExt(tif->tif_clientdata, module,
376       "Error with WebP encoder configuration.");
377     return 0;
378   }
379 
380   return 1;
381 }
382 
383 /*
384 * Reset encoding state at the start of a strip.
385 */
386 static int
TWebPPreEncode(TIFF * tif,uint16 s)387 TWebPPreEncode(TIFF* tif, uint16 s)
388 {
389   static const char module[] = "TWebPPreEncode";
390   uint32 segment_width, segment_height;
391   WebPState *sp = EncoderState(tif);
392   TIFFDirectory* td = &tif->tif_dir;
393 
394   (void) s;
395 
396   assert(sp != NULL);
397   if( sp->state != LSTATE_INIT_ENCODE )
398     tif->tif_setupencode(tif);
399 
400   /*
401    * Set encoding parameters for this strip/tile.
402    */
403   if (isTiled(tif)) {
404     segment_width = td->td_tilewidth;
405     segment_height = td->td_tilelength;
406   } else {
407     segment_width = td->td_imagewidth;
408     segment_height = td->td_imagelength - tif->tif_row;
409     if (segment_height > td->td_rowsperstrip)
410       segment_height = td->td_rowsperstrip;
411   }
412 
413   if( segment_width > 16383 || segment_height > 16383 ) {
414       TIFFErrorExt(tif->tif_clientdata, module,
415                    "WEBP maximum image dimensions are 16383 x 16383.");
416       return 0;
417   }
418 
419   /* set up buffer for raw data */
420   /* given above check and that nSamples <= 4, buffer_size is <= 1 GB */
421   sp->buffer_size = segment_width * segment_height * sp->nSamples;
422 
423   if (sp->pBuffer != NULL) {
424       _TIFFfree(sp->pBuffer);
425       sp->pBuffer = NULL;
426   }
427 
428   sp->pBuffer = _TIFFmalloc(sp->buffer_size);
429   if( !sp->pBuffer) {
430       TIFFErrorExt(tif->tif_clientdata, module, "Cannot allocate buffer");
431       return 0;
432   }
433   sp->buffer_offset = 0;
434 
435   sp->sPicture.width = segment_width;
436   sp->sPicture.height = segment_height;
437   sp->sPicture.writer = TWebPDatasetWriter;
438   sp->sPicture.custom_ptr = tif;
439 
440   return 1;
441 }
442 
443 /*
444 * Finish off an encoded strip by flushing it.
445 */
446 static int
TWebPPostEncode(TIFF * tif)447 TWebPPostEncode(TIFF* tif)
448 {
449   static const char module[] = "WebPPostEncode";
450   int64_t stride;
451   WebPState *sp = EncoderState(tif);
452   assert(sp != NULL);
453 
454   assert(sp->state == LSTATE_INIT_ENCODE);
455 
456   stride = (int64_t)sp->sPicture.width * sp->nSamples;
457 
458 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
459   if (sp->nSamples == 4) {
460       if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride)) {
461           TIFFErrorExt(tif->tif_clientdata, module,
462                     "WebPPictureImportRGBA() failed" );
463           return 0;
464       }
465   }
466   else
467 #endif
468   if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride)) {
469       TIFFErrorExt(tif->tif_clientdata, module,
470                     "WebPPictureImportRGB() failed");
471       return 0;
472   }
473 
474   if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture)) {
475 
476 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
477     const char* pszErrorMsg = NULL;
478     switch(sp->sPicture.error_code) {
479     case VP8_ENC_ERROR_OUT_OF_MEMORY:
480         pszErrorMsg = "Out of memory"; break;
481     case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
482         pszErrorMsg = "Out of memory while flushing bits"; break;
483     case VP8_ENC_ERROR_NULL_PARAMETER:
484         pszErrorMsg = "A pointer parameter is NULL"; break;
485     case VP8_ENC_ERROR_INVALID_CONFIGURATION:
486         pszErrorMsg = "Configuration is invalid"; break;
487     case VP8_ENC_ERROR_BAD_DIMENSION:
488         pszErrorMsg = "Picture has invalid width/height"; break;
489     case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
490         pszErrorMsg = "Partition is bigger than 512k. Try using less "
491             "SEGMENTS, or increase PARTITION_LIMIT value";
492         break;
493     case VP8_ENC_ERROR_PARTITION_OVERFLOW:
494         pszErrorMsg = "Partition is bigger than 16M";
495         break;
496     case VP8_ENC_ERROR_BAD_WRITE:
497         pszErrorMsg = "Error while fludshing bytes"; break;
498     case VP8_ENC_ERROR_FILE_TOO_BIG:
499         pszErrorMsg = "File is bigger than 4G"; break;
500     case VP8_ENC_ERROR_USER_ABORT:
501         pszErrorMsg = "User interrupted";
502         break;
503     default:
504         TIFFErrorExt(tif->tif_clientdata, module,
505                 "WebPEncode returned an unknown error code: %d",
506                 sp->sPicture.error_code);
507         pszErrorMsg = "Unknown WebP error type.";
508         break;
509     }
510     TIFFErrorExt(tif->tif_clientdata, module,
511              "WebPEncode() failed : %s", pszErrorMsg);
512 #else
513     TIFFErrorExt(tif->tif_clientdata, module,
514              "Error in WebPEncode()");
515 #endif
516     return 0;
517   }
518 
519   sp->sPicture.custom_ptr = NULL;
520 
521   if (!TIFFFlushData1(tif))
522   {
523     TIFFErrorExt(tif->tif_clientdata, module,
524       "Error flushing TIFF WebP encoder.");
525     return 0;
526   }
527 
528   return 1;
529 }
530 
531 static void
TWebPCleanup(TIFF * tif)532 TWebPCleanup(TIFF* tif)
533 {
534   WebPState* sp = LState(tif);
535 
536   assert(sp != 0);
537 
538   tif->tif_tagmethods.vgetfield = sp->vgetparent;
539   tif->tif_tagmethods.vsetfield = sp->vsetparent;
540 
541   if (sp->state & LSTATE_INIT_ENCODE) {
542     WebPPictureFree(&sp->sPicture);
543   }
544 
545   if (sp->psDecoder != NULL) {
546     WebPIDelete(sp->psDecoder);
547     WebPFreeDecBuffer(&sp->sDecBuffer);
548     sp->psDecoder = NULL;
549     sp->last_y = 0;
550   }
551 
552   if (sp->pBuffer != NULL) {
553       _TIFFfree(sp->pBuffer);
554       sp->pBuffer = NULL;
555   }
556 
557   _TIFFfree(tif->tif_data);
558   tif->tif_data = NULL;
559 
560   _TIFFSetDefaultCompressionState(tif);
561 }
562 
563 static int
TWebPVSetField(TIFF * tif,uint32 tag,va_list ap)564 TWebPVSetField(TIFF* tif, uint32 tag, va_list ap)
565 {
566 	static const char module[] = "WebPVSetField";
567   WebPState* sp = LState(tif);
568 
569   switch (tag) {
570   case TIFFTAG_WEBP_LEVEL:
571     sp->quality_level = (int) va_arg(ap, int);
572     if( sp->quality_level <= 0 ||
573         sp->quality_level > 100.0f ) {
574       TIFFWarningExt(tif->tif_clientdata, module,
575                      "WEBP_LEVEL should be between 1 and 100");
576     }
577     return 1;
578   case TIFFTAG_WEBP_LOSSLESS:
579     #if WEBP_ENCODER_ABI_VERSION >= 0x0100
580     sp->lossless = va_arg(ap, int);
581     if (sp->lossless){
582       sp->quality_level = 100.0f;
583     }
584     return 1;
585     #else
586       TIFFErrorExt(tif->tif_clientdata, module,
587                   "Need to upgrade WEBP driver, this version doesn't support "
588                   "lossless compression.");
589       return 0;
590     #endif
591   default:
592     return (*sp->vsetparent)(tif, tag, ap);
593   }
594   /*NOTREACHED*/
595 }
596 
597 static int
TWebPVGetField(TIFF * tif,uint32 tag,va_list ap)598 TWebPVGetField(TIFF* tif, uint32 tag, va_list ap)
599 {
600   WebPState* sp = LState(tif);
601 
602   switch (tag) {
603   case TIFFTAG_WEBP_LEVEL:
604     *va_arg(ap, int*) = sp->quality_level;
605     break;
606   case TIFFTAG_WEBP_LOSSLESS:
607     *va_arg(ap, int*) = sp->lossless;
608     break;
609   default:
610     return (*sp->vgetparent)(tif, tag, ap);
611   }
612   return 1;
613 }
614 
615 static const TIFFField TWebPFields[] = {
616   { TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
617     TIFF_SETGET_UNDEFINED,
618     FIELD_PSEUDO, TRUE, FALSE, "WEBP quality", NULL },
619   { TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
620     TIFF_SETGET_UNDEFINED,
621     FIELD_PSEUDO, TRUE, FALSE, "WEBP lossless/lossy", NULL
622   },
623 };
624 
625 int
TIFFInitWebP(TIFF * tif,int scheme)626 TIFFInitWebP(TIFF* tif, int scheme)
627 {
628   static const char module[] = "TIFFInitWebP";
629   WebPState* sp;
630 
631   assert( scheme == COMPRESSION_WEBP );
632 
633   /*
634   * Merge codec-specific tag information.
635   */
636   if ( !_TIFFMergeFields(tif, TWebPFields, TIFFArrayCount(TWebPFields)) ) {
637     TIFFErrorExt(tif->tif_clientdata, module,
638                 "Merging WebP codec-specific tags failed");
639     return 0;
640   }
641 
642   /*
643   * Allocate state block so tag methods have storage to record values.
644   */
645   tif->tif_data = (uint8*) _TIFFmalloc(sizeof(WebPState));
646   if (tif->tif_data == NULL)
647     goto bad;
648   sp = LState(tif);
649 
650   /*
651   * Override parent get/set field methods.
652   */
653   sp->vgetparent = tif->tif_tagmethods.vgetfield;
654   tif->tif_tagmethods.vgetfield = TWebPVGetField;	/* hook for codec tags */
655   sp->vsetparent = tif->tif_tagmethods.vsetfield;
656   tif->tif_tagmethods.vsetfield = TWebPVSetField;	/* hook for codec tags */
657 
658   /* Default values for codec-specific fields */
659   sp->quality_level = 75.0f;		/* default comp. level */
660   sp->lossless = 0; /* default to false */
661   sp->state = 0;
662   sp->nSamples = 0;
663   sp->psDecoder = NULL;
664   sp->last_y = 0;
665 
666   sp->buffer_offset = 0;
667   sp->pBuffer = NULL;
668 
669   /*
670   * Install codec methods.
671   * Notes:
672   * encoderow is not supported
673   */
674   tif->tif_fixuptags = TWebPFixupTags;
675   tif->tif_setupdecode = TWebPSetupDecode;
676   tif->tif_predecode = TWebPPreDecode;
677   tif->tif_decoderow = TWebPDecode;
678   tif->tif_decodestrip = TWebPDecode;
679   tif->tif_decodetile = TWebPDecode;
680   tif->tif_setupencode = TWebPSetupEncode;
681   tif->tif_preencode = TWebPPreEncode;
682   tif->tif_postencode = TWebPPostEncode;
683   tif->tif_encoderow = TWebPEncode;
684   tif->tif_encodestrip = TWebPEncode;
685   tif->tif_encodetile = TWebPEncode;
686   tif->tif_cleanup = TWebPCleanup;
687 
688   return 1;
689 bad:
690   TIFFErrorExt(tif->tif_clientdata, module,
691   	     "No space for WebP state block");
692   return 0;
693 }
694 
695 #endif /* WEBP_SUPPORT */
696