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, ¤t_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 */
|