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