opencv

Форк
0
/
tif_webp.c 
881 строка · 25.2 Кб
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
static int TWebPDatasetWriter(const uint8_t *data, size_t data_size,
78
                              const WebPPicture *const picture)
79
{
80
    static const char module[] = "TWebPDatasetWriter";
81
    TIFF *tif = (TIFF *)(picture->custom_ptr);
82

83
    if ((tif->tif_rawcc + (tmsize_t)data_size) > tif->tif_rawdatasize)
84
    {
85
        TIFFErrorExtR(
86
            tif, module, "Buffer too small by %" TIFF_SIZE_FORMAT " bytes.",
87
            (size_t)(tif->tif_rawcc + data_size - tif->tif_rawdatasize));
88
        return 0;
89
    }
90
    else
91
    {
92
        _TIFFmemcpy(tif->tif_rawcp, data, data_size);
93
        tif->tif_rawcc += data_size;
94
        tif->tif_rawcp += data_size;
95
        return 1;
96
    }
97
}
98

99
/*
100
 * Encode a chunk of pixels.
101
 */
102
static int TWebPEncode(TIFF *tif, uint8_t *bp, tmsize_t cc, uint16_t s)
103
{
104
    static const char module[] = "TWebPEncode";
105
    WebPState *sp = EncoderState(tif);
106
    (void)s;
107

108
    assert(sp != NULL);
109
    assert(sp->state == LSTATE_INIT_ENCODE);
110

111
    if ((uint64_t)sp->buffer_offset + (uint64_t)cc > sp->buffer_size)
112
    {
113
        TIFFErrorExtR(tif, module, "Too many bytes to be written");
114
        return 0;
115
    }
116

117
    memcpy(sp->pBuffer + sp->buffer_offset, bp, cc);
118
    sp->buffer_offset += (unsigned)cc;
119

120
    return 1;
121
}
122

123
static int TWebPDecode(TIFF *tif, uint8_t *op, tmsize_t occ, uint16_t s)
124
{
125
    static const char module[] = "WebPDecode";
126
    VP8StatusCode status = VP8_STATUS_OK;
127
    WebPState *sp = DecoderState(tif);
128
    uint32_t segment_width, segment_height;
129
    bool decode_whole_strile = false;
130

131
    (void)s;
132

133
    assert(sp != NULL);
134
    assert(sp->state == LSTATE_INIT_DECODE);
135

136
    if (sp->psDecoder == NULL)
137
    {
138
        TIFFDirectory *td = &tif->tif_dir;
139
        uint32_t buffer_size;
140

141
        if (isTiled(tif))
142
        {
143
            segment_width = td->td_tilewidth;
144
            segment_height = td->td_tilelength;
145
        }
146
        else
147
        {
148
            segment_width = td->td_imagewidth;
149
            segment_height = td->td_imagelength - tif->tif_row;
150
            if (segment_height > td->td_rowsperstrip)
151
                segment_height = td->td_rowsperstrip;
152
        }
153

154
        int webp_width, webp_height;
155
        if (!WebPGetInfo(tif->tif_rawcp,
156
                         (uint64_t)tif->tif_rawcc > UINT32_MAX
157
                             ? UINT32_MAX
158
                             : (uint32_t)tif->tif_rawcc,
159
                         &webp_width, &webp_height))
160
        {
161
            TIFFErrorExtR(tif, module, "WebPGetInfo() failed");
162
            return 0;
163
        }
164
        if ((uint32_t)webp_width != segment_width ||
165
            (uint32_t)webp_height != segment_height)
166
        {
167
            TIFFErrorExtR(
168
                tif, module, "WebP blob dimension is %dx%d. Expected %ux%u",
169
                webp_width, webp_height, segment_width, segment_height);
170
            return 0;
171
        }
172

173
#if WEBP_DECODER_ABI_VERSION >= 0x0002
174
        WebPDecoderConfig config;
175
        if (!WebPInitDecoderConfig(&config))
176
        {
177
            TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
178
            return 0;
179
        }
180

181
        const bool bWebPGetFeaturesOK =
182
            WebPGetFeatures(tif->tif_rawcp,
183
                            (uint64_t)tif->tif_rawcc > UINT32_MAX
184
                                ? UINT32_MAX
185
                                : (uint32_t)tif->tif_rawcc,
186
                            &config.input) == VP8_STATUS_OK;
187

188
        WebPFreeDecBuffer(&config.output);
189

190
        if (!bWebPGetFeaturesOK)
191
        {
192
            TIFFErrorExtR(tif, module, "WebPInitDecoderConfig() failed");
193
            return 0;
194
        }
195

196
        const int webp_bands = config.input.has_alpha ? 4 : 3;
197
        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
            !(webp_bands == 3 && sp->nSamples == 4))
204
        {
205
            TIFFErrorExtR(tif, module,
206
                          "WebP blob band count is %d. Expected %d", webp_bands,
207
                          sp->nSamples);
208
            return 0;
209
        }
210
#endif
211

212
        buffer_size = segment_width * segment_height * sp->nSamples;
213
        if (occ == (tmsize_t)buffer_size)
214
        {
215
            /* If decoding the whole strip/tile, we can directly use the */
216
            /* output buffer */
217
            decode_whole_strile = true;
218
        }
219
        else if (sp->pBuffer == NULL || buffer_size > sp->buffer_size)
220
        {
221
            if (sp->pBuffer != NULL)
222
            {
223
                _TIFFfreeExt(tif, sp->pBuffer);
224
                sp->pBuffer = NULL;
225
            }
226

227
            sp->pBuffer = _TIFFmallocExt(tif, buffer_size);
228
            if (!sp->pBuffer)
229
            {
230
                TIFFErrorExtR(tif, module, "Cannot allocate buffer");
231
                return 0;
232
            }
233
            sp->buffer_size = buffer_size;
234
        }
235

236
        sp->last_y = 0;
237

238
        WebPInitDecBuffer(&sp->sDecBuffer);
239

240
        sp->sDecBuffer.is_external_memory = 1;
241
        sp->sDecBuffer.width = segment_width;
242
        sp->sDecBuffer.height = segment_height;
243
        sp->sDecBuffer.u.RGBA.rgba = decode_whole_strile ? op : sp->pBuffer;
244
        sp->sDecBuffer.u.RGBA.stride = segment_width * sp->nSamples;
245
        sp->sDecBuffer.u.RGBA.size = buffer_size;
246

247
        if (sp->nSamples > 3)
248
        {
249
            sp->sDecBuffer.colorspace = MODE_RGBA;
250
        }
251
        else
252
        {
253
            sp->sDecBuffer.colorspace = MODE_RGB;
254
        }
255

256
        sp->psDecoder = WebPINewDecoder(&sp->sDecBuffer);
257

258
        if (sp->psDecoder == NULL)
259
        {
260
            TIFFErrorExtR(tif, module, "Unable to allocate WebP decoder.");
261
            return 0;
262
        }
263
    }
264

265
    if (occ % sp->sDecBuffer.u.RGBA.stride)
266
    {
267
        TIFFErrorExtR(tif, module, "Fractional scanlines cannot be read");
268
        return 0;
269
    }
270

271
    status = WebPIAppend(sp->psDecoder, tif->tif_rawcp, tif->tif_rawcc);
272

273
    if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED)
274
    {
275
        if (status == VP8_STATUS_INVALID_PARAM)
276
        {
277
            TIFFErrorExtR(tif, module, "Invalid parameter used.");
278
        }
279
        else if (status == VP8_STATUS_OUT_OF_MEMORY)
280
        {
281
            TIFFErrorExtR(tif, module, "Out of memory.");
282
        }
283
        else
284
        {
285
            TIFFErrorExtR(tif, module, "Unrecognized error.");
286
        }
287
        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
        buf = WebPIDecGetRGB(sp->psDecoder, &current_y, NULL, NULL, &stride);
296

297
        if ((buf != NULL) &&
298
            (occ <= (tmsize_t)stride * (current_y - sp->last_y)))
299
        {
300
            const int numberOfExpectedLines =
301
                (int)(occ / sp->sDecBuffer.u.RGBA.stride);
302
            if (decode_whole_strile)
303
            {
304
                if (current_y != numberOfExpectedLines)
305
                {
306
                    TIFFErrorExtR(tif, module,
307
                                  "Unable to decode WebP data: less lines than "
308
                                  "expected.");
309
                    return 0;
310
                }
311
            }
312
            else
313
            {
314
                memcpy(op, buf + (sp->last_y * stride), occ);
315
            }
316

317
            tif->tif_rawcp += tif->tif_rawcc;
318
            tif->tif_rawcc = 0;
319
            sp->last_y += numberOfExpectedLines;
320

321
            if (decode_whole_strile)
322
            {
323
                /* We can now free the decoder as we're completely done */
324
                if (sp->psDecoder != NULL)
325
                {
326
                    WebPIDelete(sp->psDecoder);
327
                    WebPFreeDecBuffer(&sp->sDecBuffer);
328
                    sp->psDecoder = NULL;
329
                }
330
            }
331
            return 1;
332
        }
333
        else
334
        {
335
            TIFFErrorExtR(tif, module, "Unable to decode WebP data.");
336
            return 0;
337
        }
338
    }
339
}
340

341
static int TWebPFixupTags(TIFF *tif)
342
{
343
    (void)tif;
344
    if (tif->tif_dir.td_planarconfig != PLANARCONFIG_CONTIG)
345
    {
346
        static const char module[] = "TWebPFixupTags";
347
        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
        return 0;
355
    }
356
    return 1;
357
}
358

359
static int TWebPSetupDecode(TIFF *tif)
360
{
361
    static const char module[] = "WebPSetupDecode";
362
    uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample;
363
    uint16_t sampleFormat = tif->tif_dir.td_sampleformat;
364

365
    WebPState *sp = DecoderState(tif);
366
    assert(sp != NULL);
367

368
    sp->nSamples = tif->tif_dir.td_samplesperpixel;
369

370
    /* check band count */
371
    if (sp->nSamples != 3
372
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
373
        && sp->nSamples != 4
374
#endif
375
    )
376
    {
377
        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
                      sp->nSamples);
384
        return 0;
385
    }
386

387
    /* check bits per sample and data type */
388
    if ((nBitsPerSample != 8) && (sampleFormat != 1))
389
    {
390
        TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data");
391
        return 0;
392
    }
393

394
    /* if we were last encoding, terminate this mode */
395
    if (sp->state & LSTATE_INIT_ENCODE)
396
    {
397
        WebPPictureFree(&sp->sPicture);
398
        if (sp->pBuffer != NULL)
399
        {
400
            _TIFFfreeExt(tif, sp->pBuffer);
401
            sp->pBuffer = NULL;
402
        }
403
        sp->buffer_offset = 0;
404
        sp->state = 0;
405
    }
406

407
    sp->state |= LSTATE_INIT_DECODE;
408

409
    return 1;
410
}
411

412
/*
413
 * Setup state for decoding a strip.
414
 */
415
static int TWebPPreDecode(TIFF *tif, uint16_t s)
416
{
417
    static const char module[] = "TWebPPreDecode";
418
    uint32_t segment_width, segment_height;
419
    WebPState *sp = DecoderState(tif);
420
    TIFFDirectory *td = &tif->tif_dir;
421
    (void)s;
422
    assert(sp != NULL);
423

424
    if (isTiled(tif))
425
    {
426
        segment_width = td->td_tilewidth;
427
        segment_height = td->td_tilelength;
428
    }
429
    else
430
    {
431
        segment_width = td->td_imagewidth;
432
        segment_height = td->td_imagelength - tif->tif_row;
433
        if (segment_height > td->td_rowsperstrip)
434
            segment_height = td->td_rowsperstrip;
435
    }
436

437
    if (segment_width > 16383 || segment_height > 16383)
438
    {
439
        TIFFErrorExtR(tif, module,
440
                      "WEBP maximum image dimensions are 16383 x 16383.");
441
        return 0;
442
    }
443

444
    if ((sp->state & LSTATE_INIT_DECODE) == 0)
445
        tif->tif_setupdecode(tif);
446

447
    if (sp->psDecoder != NULL)
448
    {
449
        WebPIDelete(sp->psDecoder);
450
        WebPFreeDecBuffer(&sp->sDecBuffer);
451
        sp->psDecoder = NULL;
452
    }
453

454
    return 1;
455
}
456

457
static int TWebPSetupEncode(TIFF *tif)
458
{
459
    static const char module[] = "WebPSetupEncode";
460
    uint16_t nBitsPerSample = tif->tif_dir.td_bitspersample;
461
    uint16_t sampleFormat = tif->tif_dir.td_sampleformat;
462

463
    WebPState *sp = EncoderState(tif);
464
    assert(sp != NULL);
465

466
    sp->nSamples = tif->tif_dir.td_samplesperpixel;
467

468
    /* check band count */
469
    if (sp->nSamples != 3
470
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
471
        && sp->nSamples != 4
472
#endif
473
    )
474
    {
475
        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
                      sp->nSamples);
482
        return 0;
483
    }
484

485
    /* check bits per sample and data type */
486
    if ((nBitsPerSample != 8) || (sampleFormat != SAMPLEFORMAT_UINT))
487
    {
488
        TIFFErrorExtR(tif, module, "WEBP driver requires 8 bit unsigned data");
489
        return 0;
490
    }
491

492
    if (sp->state & LSTATE_INIT_DECODE)
493
    {
494
        WebPIDelete(sp->psDecoder);
495
        WebPFreeDecBuffer(&sp->sDecBuffer);
496
        sp->psDecoder = NULL;
497
        sp->last_y = 0;
498
        sp->state = 0;
499
    }
500

501
    sp->state |= LSTATE_INIT_ENCODE;
502

503
    if (!WebPPictureInit(&sp->sPicture))
504
    {
505
        TIFFErrorExtR(tif, module, "Error initializing WebP picture.");
506
        return 0;
507
    }
508

509
    if (!WebPConfigInitInternal(&sp->sEncoderConfig, WEBP_PRESET_DEFAULT,
510
                                (float)sp->quality_level,
511
                                WEBP_ENCODER_ABI_VERSION))
512
    {
513
        TIFFErrorExtR(tif, module,
514
                      "Error creating WebP encoder configuration.");
515
        return 0;
516
    }
517

518
// WebPConfigInitInternal above sets lossless to false
519
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
520
    sp->sEncoderConfig.lossless = sp->lossless;
521
    if (sp->lossless)
522
    {
523
        sp->sPicture.use_argb = 1;
524
#if WEBP_ENCODER_ABI_VERSION >= 0x0209
525
        sp->sEncoderConfig.exact = sp->lossless_exact;
526
#endif
527
    }
528
#endif
529

530
    if (!WebPValidateConfig(&sp->sEncoderConfig))
531
    {
532
        TIFFErrorExtR(tif, module, "Error with WebP encoder configuration.");
533
        return 0;
534
    }
535

536
    return 1;
537
}
538

539
/*
540
 * Reset encoding state at the start of a strip.
541
 */
542
static int TWebPPreEncode(TIFF *tif, uint16_t s)
543
{
544
    static const char module[] = "TWebPPreEncode";
545
    uint32_t segment_width, segment_height;
546
    WebPState *sp = EncoderState(tif);
547
    TIFFDirectory *td = &tif->tif_dir;
548

549
    (void)s;
550

551
    assert(sp != NULL);
552
    if (sp->state != LSTATE_INIT_ENCODE)
553
        tif->tif_setupencode(tif);
554

555
    /*
556
     * Set encoding parameters for this strip/tile.
557
     */
558
    if (isTiled(tif))
559
    {
560
        segment_width = td->td_tilewidth;
561
        segment_height = td->td_tilelength;
562
    }
563
    else
564
    {
565
        segment_width = td->td_imagewidth;
566
        segment_height = td->td_imagelength - tif->tif_row;
567
        if (segment_height > td->td_rowsperstrip)
568
            segment_height = td->td_rowsperstrip;
569
    }
570

571
    if (segment_width > 16383 || segment_height > 16383)
572
    {
573
        TIFFErrorExtR(tif, module,
574
                      "WEBP maximum image dimensions are 16383 x 16383.");
575
        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
    sp->buffer_size = segment_width * segment_height * sp->nSamples;
581

582
    if (sp->pBuffer != NULL)
583
    {
584
        _TIFFfreeExt(tif, sp->pBuffer);
585
        sp->pBuffer = NULL;
586
    }
587

588
    sp->pBuffer = _TIFFmallocExt(tif, sp->buffer_size);
589
    if (!sp->pBuffer)
590
    {
591
        TIFFErrorExtR(tif, module, "Cannot allocate buffer");
592
        return 0;
593
    }
594
    sp->buffer_offset = 0;
595

596
    sp->sPicture.width = segment_width;
597
    sp->sPicture.height = segment_height;
598
    sp->sPicture.writer = TWebPDatasetWriter;
599
    sp->sPicture.custom_ptr = tif;
600

601
    return 1;
602
}
603

604
/*
605
 * Finish off an encoded strip by flushing it.
606
 */
607
static int TWebPPostEncode(TIFF *tif)
608
{
609
    static const char module[] = "WebPPostEncode";
610
    int64_t stride;
611
    WebPState *sp = EncoderState(tif);
612
    assert(sp != NULL);
613

614
    assert(sp->state == LSTATE_INIT_ENCODE);
615

616
    stride = (int64_t)sp->sPicture.width * sp->nSamples;
617

618
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
619
    if (sp->nSamples == 4)
620
    {
621
        if (!WebPPictureImportRGBA(&sp->sPicture, sp->pBuffer, (int)stride))
622
        {
623
            TIFFErrorExtR(tif, module, "WebPPictureImportRGBA() failed");
624
            return 0;
625
        }
626
    }
627
    else
628
#endif
629
        if (!WebPPictureImportRGB(&sp->sPicture, sp->pBuffer, (int)stride))
630
    {
631
        TIFFErrorExtR(tif, module, "WebPPictureImportRGB() failed");
632
        return 0;
633
    }
634

635
    if (!WebPEncode(&sp->sEncoderConfig, &sp->sPicture))
636
    {
637

638
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
639
        const char *pszErrorMsg = NULL;
640
        switch (sp->sPicture.error_code)
641
        {
642
            case VP8_ENC_ERROR_OUT_OF_MEMORY:
643
                pszErrorMsg = "Out of memory";
644
                break;
645
            case VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY:
646
                pszErrorMsg = "Out of memory while flushing bits";
647
                break;
648
            case VP8_ENC_ERROR_NULL_PARAMETER:
649
                pszErrorMsg = "A pointer parameter is NULL";
650
                break;
651
            case VP8_ENC_ERROR_INVALID_CONFIGURATION:
652
                pszErrorMsg = "Configuration is invalid";
653
                break;
654
            case VP8_ENC_ERROR_BAD_DIMENSION:
655
                pszErrorMsg = "Picture has invalid width/height";
656
                break;
657
            case VP8_ENC_ERROR_PARTITION0_OVERFLOW:
658
                pszErrorMsg = "Partition is bigger than 512k. Try using less "
659
                              "SEGMENTS, or increase PARTITION_LIMIT value";
660
                break;
661
            case VP8_ENC_ERROR_PARTITION_OVERFLOW:
662
                pszErrorMsg = "Partition is bigger than 16M";
663
                break;
664
            case VP8_ENC_ERROR_BAD_WRITE:
665
                pszErrorMsg = "Error while fludshing bytes";
666
                break;
667
            case VP8_ENC_ERROR_FILE_TOO_BIG:
668
                pszErrorMsg = "File is bigger than 4G";
669
                break;
670
            case VP8_ENC_ERROR_USER_ABORT:
671
                pszErrorMsg = "User interrupted";
672
                break;
673
            default:
674
                TIFFErrorExtR(tif, module,
675
                              "WebPEncode returned an unknown error code: %d",
676
                              sp->sPicture.error_code);
677
                pszErrorMsg = "Unknown WebP error type.";
678
                break;
679
        }
680
        TIFFErrorExtR(tif, module, "WebPEncode() failed : %s", pszErrorMsg);
681
#else
682
        TIFFErrorExtR(tif, module, "Error in WebPEncode()");
683
#endif
684
        return 0;
685
    }
686

687
    sp->sPicture.custom_ptr = NULL;
688

689
    if (!TIFFFlushData1(tif))
690
    {
691
        TIFFErrorExtR(tif, module, "Error flushing TIFF WebP encoder.");
692
        return 0;
693
    }
694

695
    return 1;
696
}
697

698
static void TWebPCleanup(TIFF *tif)
699
{
700
    WebPState *sp = LState(tif);
701

702
    assert(sp != 0);
703

704
    tif->tif_tagmethods.vgetfield = sp->vgetparent;
705
    tif->tif_tagmethods.vsetfield = sp->vsetparent;
706

707
    if (sp->state & LSTATE_INIT_ENCODE)
708
    {
709
        WebPPictureFree(&sp->sPicture);
710
    }
711

712
    if (sp->psDecoder != NULL)
713
    {
714
        WebPIDelete(sp->psDecoder);
715
        WebPFreeDecBuffer(&sp->sDecBuffer);
716
        sp->psDecoder = NULL;
717
        sp->last_y = 0;
718
    }
719

720
    if (sp->pBuffer != NULL)
721
    {
722
        _TIFFfreeExt(tif, sp->pBuffer);
723
        sp->pBuffer = NULL;
724
    }
725

726
    _TIFFfreeExt(tif, tif->tif_data);
727
    tif->tif_data = NULL;
728

729
    _TIFFSetDefaultCompressionState(tif);
730
}
731

732
static int TWebPVSetField(TIFF *tif, uint32_t tag, va_list ap)
733
{
734
    static const char module[] = "WebPVSetField";
735
    WebPState *sp = LState(tif);
736

737
    switch (tag)
738
    {
739
        case TIFFTAG_WEBP_LEVEL:
740
            sp->quality_level = (int)va_arg(ap, int);
741
            if (sp->quality_level <= 0 || sp->quality_level > 100.0f)
742
            {
743
                TIFFWarningExtR(tif, module,
744
                                "WEBP_LEVEL should be between 1 and 100");
745
            }
746
            return 1;
747
        case TIFFTAG_WEBP_LOSSLESS:
748
#if WEBP_ENCODER_ABI_VERSION >= 0x0100
749
            sp->lossless = va_arg(ap, int);
750
            if (sp->lossless)
751
            {
752
                sp->quality_level = 100;
753
            }
754
            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
        case TIFFTAG_WEBP_LOSSLESS_EXACT:
763
#if WEBP_ENCODER_ABI_VERSION >= 0x0209
764
            sp->lossless_exact = va_arg(ap, int);
765
            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
        default:
774
            return (*sp->vsetparent)(tif, tag, ap);
775
    }
776
    /*NOTREACHED*/
777
}
778

779
static int TWebPVGetField(TIFF *tif, uint32_t tag, va_list ap)
780
{
781
    WebPState *sp = LState(tif);
782

783
    switch (tag)
784
    {
785
        case TIFFTAG_WEBP_LEVEL:
786
            *va_arg(ap, int *) = sp->quality_level;
787
            break;
788
        case TIFFTAG_WEBP_LOSSLESS:
789
            *va_arg(ap, int *) = sp->lossless;
790
            break;
791
        case TIFFTAG_WEBP_LOSSLESS_EXACT:
792
            *va_arg(ap, int *) = sp->lossless_exact;
793
            break;
794
        default:
795
            return (*sp->vgetparent)(tif, tag, ap);
796
    }
797
    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
int TIFFInitWebP(TIFF *tif, int scheme)
812
{
813
    static const char module[] = "TIFFInitWebP";
814
    WebPState *sp;
815

816
    (void)scheme;
817
    assert(scheme == COMPRESSION_WEBP);
818

819
    /*
820
     * Merge codec-specific tag information.
821
     */
822
    if (!_TIFFMergeFields(tif, TWebPFields, TIFFArrayCount(TWebPFields)))
823
    {
824
        TIFFErrorExtR(tif, module, "Merging WebP codec-specific tags failed");
825
        return 0;
826
    }
827

828
    /*
829
     * Allocate state block so tag methods have storage to record values.
830
     */
831
    tif->tif_data = (uint8_t *)_TIFFmallocExt(tif, sizeof(WebPState));
832
    if (tif->tif_data == NULL)
833
        goto bad;
834
    sp = LState(tif);
835

836
    /*
837
     * Override parent get/set field methods.
838
     */
839
    sp->vgetparent = tif->tif_tagmethods.vgetfield;
840
    tif->tif_tagmethods.vgetfield = TWebPVGetField; /* hook for codec tags */
841
    sp->vsetparent = tif->tif_tagmethods.vsetfield;
842
    tif->tif_tagmethods.vsetfield = TWebPVSetField; /* hook for codec tags */
843

844
    /* Default values for codec-specific fields */
845
    sp->quality_level = 75; /* default comp. level */
846
    sp->lossless = 0;       /* default to false */
847
    sp->lossless_exact = 1; /* exact lossless mode (if lossless enabled) */
848
    sp->state = 0;
849
    sp->nSamples = 0;
850
    sp->psDecoder = NULL;
851
    sp->last_y = 0;
852

853
    sp->buffer_offset = 0;
854
    sp->pBuffer = NULL;
855

856
    /*
857
     * Install codec methods.
858
     * Notes:
859
     * encoderow is not supported
860
     */
861
    tif->tif_fixuptags = TWebPFixupTags;
862
    tif->tif_setupdecode = TWebPSetupDecode;
863
    tif->tif_predecode = TWebPPreDecode;
864
    tif->tif_decoderow = TWebPDecode;
865
    tif->tif_decodestrip = TWebPDecode;
866
    tif->tif_decodetile = TWebPDecode;
867
    tif->tif_setupencode = TWebPSetupEncode;
868
    tif->tif_preencode = TWebPPreEncode;
869
    tif->tif_postencode = TWebPPostEncode;
870
    tif->tif_encoderow = TWebPEncode;
871
    tif->tif_encodestrip = TWebPEncode;
872
    tif->tif_encodetile = TWebPEncode;
873
    tif->tif_cleanup = TWebPCleanup;
874

875
    return 1;
876
bad:
877
    TIFFErrorExtR(tif, module, "No space for WebP state block");
878
    return 0;
879
}
880

881
#endif /* WEBP_SUPPORT */
882

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.