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