[LOCALSPL_WINETEST] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / 3rdparty / libtiff / tif_webp.c
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
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
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
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
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
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
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
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 (!WebPConfigInitInternal(&sp->sEncoderConfig, WEBP_PRESET_DEFAULT,
353 sp->quality_level,
354 WEBP_ENCODER_ABI_VERSION)) {
355 TIFFErrorExt(tif->tif_clientdata, module,
356 "Error creating WebP encoder configuration.");
357 return 0;
358 }
359
360 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
361 sp->sEncoderConfig.lossless = sp->lossless;
362 #endif
363
364 if (!WebPValidateConfig(&sp->sEncoderConfig)) {
365 TIFFErrorExt(tif->tif_clientdata, module,
366 "Error with WebP encoder configuration.");
367 return 0;
368 }
369
370 if (!WebPPictureInit(&sp->sPicture)) {
371 TIFFErrorExt(tif->tif_clientdata, module,
372 "Error initializing WebP picture.");
373 return 0;
374 }
375
376 return 1;
377 }
378
379 /*
380 * Reset encoding state at the start of a strip.
381 */
382 static int
383 TWebPPreEncode(TIFF* tif, uint16 s)
384 {
385 static const char module[] = "TWebPPreEncode";
386 uint32 segment_width, segment_height;
387 WebPState *sp = EncoderState(tif);
388 TIFFDirectory* td = &tif->tif_dir;
389
390 (void) s;
391
392 assert(sp != NULL);
393 if( sp->state != LSTATE_INIT_ENCODE )
394 tif->tif_setupencode(tif);
395
396 /*
397 * Set encoding parameters for this strip/tile.
398 */
399 if (isTiled(tif)) {
400 segment_width = td->td_tilewidth;
401 segment_height = td->td_tilelength;
402 } else {
403 segment_width = td->td_imagewidth;
404 segment_height = td->td_imagelength - tif->tif_row;
405 if (segment_height > td->td_rowsperstrip)
406 segment_height = td->td_rowsperstrip;
407 }
408
409 if( segment_width > 16383 || segment_height > 16383 ) {
410 TIFFErrorExt(tif->tif_clientdata, module,
411 "WEBP maximum image dimensions are 16383 x 16383.");
412 return 0;
413 }
414
415 /* set up buffer for raw data */
416 /* given above check and that nSamples <= 4, buffer_size is <= 1 GB */
417 sp->buffer_size = segment_width * segment_height * sp->nSamples;
418 sp->pBuffer = _TIFFmalloc(sp->buffer_size);
419 if( !sp->pBuffer) {
420 TIFFErrorExt(tif->tif_clientdata, module, "Cannot allocate buffer");
421 return 0;
422 }
423 sp->buffer_offset = 0;
424
425 sp->sPicture.width = segment_width;
426 sp->sPicture.height = segment_height;
427 sp->sPicture.writer = TWebPDatasetWriter;
428 sp->sPicture.custom_ptr = tif;
429
430 return 1;
431 }
432
433 /*
434 * Finish off an encoded strip by flushing it.
435 */
436 static int
437 TWebPPostEncode(TIFF* tif)
438 {
439 static const char module[] = "WebPPostEncode";
440 int64_t stride;
441 WebPState *sp = EncoderState(tif);
442 assert(sp != NULL);
443
444 assert(sp->state == LSTATE_INIT_ENCODE);
445
446 stride = (int64_t)sp->sPicture.width * sp->nSamples;
447
448 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
449 if (sp->nSamples == 4) {
450 if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride)) {
451 TIFFErrorExt(tif->tif_clientdata, module,
452 "WebPPictureImportRGBA() failed" );
453 return 0;
454 }
455 }
456 else
457 #endif
458 if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride)) {
459 TIFFErrorExt(tif->tif_clientdata, module,
460 "WebPPictureImportRGB() failed");
461 return 0;
462 }
463
464 if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture)) {
465
466 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
467 const char* pszErrorMsg = NULL;
468 switch(sp->sPicture.error_code) {
469 case VP8_ENC_ERROR_OUT_OF_MEMORY:
470 pszErrorMsg = "Out of memory"; break;
471 case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
472 pszErrorMsg = "Out of memory while flushing bits"; break;
473 case VP8_ENC_ERROR_NULL_PARAMETER:
474 pszErrorMsg = "A pointer parameter is NULL"; break;
475 case VP8_ENC_ERROR_INVALID_CONFIGURATION:
476 pszErrorMsg = "Configuration is invalid"; break;
477 case VP8_ENC_ERROR_BAD_DIMENSION:
478 pszErrorMsg = "Picture has invalid width/height"; break;
479 case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
480 pszErrorMsg = "Partition is bigger than 512k. Try using less "
481 "SEGMENTS, or increase PARTITION_LIMIT value";
482 break;
483 case VP8_ENC_ERROR_PARTITION_OVERFLOW:
484 pszErrorMsg = "Partition is bigger than 16M";
485 break;
486 case VP8_ENC_ERROR_BAD_WRITE:
487 pszErrorMsg = "Error while fludshing bytes"; break;
488 case VP8_ENC_ERROR_FILE_TOO_BIG:
489 pszErrorMsg = "File is bigger than 4G"; break;
490 case VP8_ENC_ERROR_USER_ABORT:
491 pszErrorMsg = "User interrupted";
492 break;
493 default:
494 TIFFErrorExt(tif->tif_clientdata, module,
495 "WebPEncode returned an unknown error code: %d",
496 sp->sPicture.error_code);
497 pszErrorMsg = "Unknown WebP error type.";
498 break;
499 }
500 TIFFErrorExt(tif->tif_clientdata, module,
501 "WebPEncode() failed : %s", pszErrorMsg);
502 #else
503 TIFFErrorExt(tif->tif_clientdata, module,
504 "Error in WebPEncode()");
505 #endif
506 return 0;
507 }
508
509 sp->sPicture.custom_ptr = NULL;
510
511 if (!TIFFFlushData1(tif))
512 {
513 TIFFErrorExt(tif->tif_clientdata, module,
514 "Error flushing TIFF WebP encoder.");
515 return 0;
516 }
517
518 return 1;
519 }
520
521 static void
522 TWebPCleanup(TIFF* tif)
523 {
524 WebPState* sp = LState(tif);
525
526 assert(sp != 0);
527
528 tif->tif_tagmethods.vgetfield = sp->vgetparent;
529 tif->tif_tagmethods.vsetfield = sp->vsetparent;
530
531 if (sp->state & LSTATE_INIT_ENCODE) {
532 WebPPictureFree(&sp->sPicture);
533 }
534
535 if (sp->psDecoder != NULL) {
536 WebPIDelete(sp->psDecoder);
537 WebPFreeDecBuffer(&sp->sDecBuffer);
538 sp->psDecoder = NULL;
539 sp->last_y = 0;
540 }
541
542 if (sp->pBuffer != NULL) {
543 _TIFFfree(sp->pBuffer);
544 sp->pBuffer = NULL;
545 }
546
547 if (tif->tif_data) {
548 _TIFFfree(tif->tif_data);
549 tif->tif_data = NULL;
550 }
551
552 _TIFFSetDefaultCompressionState(tif);
553 }
554
555 static int
556 TWebPVSetField(TIFF* tif, uint32 tag, va_list ap)
557 {
558 static const char module[] = "WebPVSetField";
559 WebPState* sp = LState(tif);
560
561 switch (tag) {
562 case TIFFTAG_WEBP_LEVEL:
563 sp->quality_level = (int) va_arg(ap, int);
564 if( sp->quality_level <= 0 ||
565 sp->quality_level > 100.0f ) {
566 TIFFWarningExt(tif->tif_clientdata, module,
567 "WEBP_LEVEL should be between 1 and 100");
568 }
569 return 1;
570 case TIFFTAG_WEBP_LOSSLESS:
571 #if WEBP_ENCODER_ABI_VERSION >= 0x0100
572 sp->lossless = va_arg(ap, int);
573 return 1;
574 #else
575 TIFFErrorExt(tif->tif_clientdata, module,
576 "Need to upgrade WEBP driver, this version doesn't support "
577 "lossless compression.");
578 return 0;
579 #endif
580 default:
581 return (*sp->vsetparent)(tif, tag, ap);
582 }
583 /*NOTREACHED*/
584 }
585
586 static int
587 TWebPVGetField(TIFF* tif, uint32 tag, va_list ap)
588 {
589 WebPState* sp = LState(tif);
590
591 switch (tag) {
592 case TIFFTAG_WEBP_LEVEL:
593 *va_arg(ap, int*) = sp->quality_level;
594 break;
595 case TIFFTAG_WEBP_LOSSLESS:
596 *va_arg(ap, int*) = sp->lossless;
597 break;
598 default:
599 return (*sp->vgetparent)(tif, tag, ap);
600 }
601 return 1;
602 }
603
604 static const TIFFField TWebPFields[] = {
605 { TIFFTAG_WEBP_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
606 TIFF_SETGET_UNDEFINED,
607 FIELD_PSEUDO, TRUE, FALSE, "WEBP quality", NULL },
608 { TIFFTAG_WEBP_LOSSLESS, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
609 TIFF_SETGET_UNDEFINED,
610 FIELD_PSEUDO, TRUE, FALSE, "WEBP lossless/lossy", NULL
611 },
612 };
613
614 int
615 TIFFInitWebP(TIFF* tif, int scheme)
616 {
617 static const char module[] = "TIFFInitWebP";
618 WebPState* sp;
619
620 assert( scheme == COMPRESSION_WEBP );
621
622 /*
623 * Merge codec-specific tag information.
624 */
625 if ( !_TIFFMergeFields(tif, TWebPFields, TIFFArrayCount(TWebPFields)) ) {
626 TIFFErrorExt(tif->tif_clientdata, module,
627 "Merging WebP codec-specific tags failed");
628 return 0;
629 }
630
631 /*
632 * Allocate state block so tag methods have storage to record values.
633 */
634 tif->tif_data = (uint8*) _TIFFmalloc(sizeof(WebPState));
635 if (tif->tif_data == NULL)
636 goto bad;
637 sp = LState(tif);
638
639 /*
640 * Override parent get/set field methods.
641 */
642 sp->vgetparent = tif->tif_tagmethods.vgetfield;
643 tif->tif_tagmethods.vgetfield = TWebPVGetField; /* hook for codec tags */
644 sp->vsetparent = tif->tif_tagmethods.vsetfield;
645 tif->tif_tagmethods.vsetfield = TWebPVSetField; /* hook for codec tags */
646
647 /* Default values for codec-specific fields */
648 sp->quality_level = 75.0f; /* default comp. level */
649 sp->lossless = 0; /* default to false */
650 sp->state = 0;
651 sp->nSamples = 0;
652 sp->psDecoder = NULL;
653 sp->last_y = 0;
654
655 sp->buffer_offset = 0;
656 sp->pBuffer = NULL;
657
658 /*
659 * Install codec methods.
660 * Notes:
661 * encoderow is not supported
662 */
663 tif->tif_fixuptags = TWebPFixupTags;
664 tif->tif_setupdecode = TWebPSetupDecode;
665 tif->tif_predecode = TWebPPreDecode;
666 tif->tif_decoderow = TWebPDecode;
667 tif->tif_decodestrip = TWebPDecode;
668 tif->tif_decodetile = TWebPDecode;
669 tif->tif_setupencode = TWebPSetupEncode;
670 tif->tif_preencode = TWebPPreEncode;
671 tif->tif_postencode = TWebPPostEncode;
672 tif->tif_encoderow = TWebPEncode;
673 tif->tif_encodestrip = TWebPEncode;
674 tif->tif_encodetile = TWebPEncode;
675 tif->tif_cleanup = TWebPCleanup;
676
677 return 1;
678 bad:
679 TIFFErrorExt(tif->tif_clientdata, module,
680 "No space for WebP state block");
681 return 0;
682 }
683
684 #endif /* WEBP_SUPPORT */