Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/images/SkWebpEncoder.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2010 The Android Open Source Project
3
 *
4
 * Use of this source code is governed by a BSD-style license that can be
5
 * found in the LICENSE file.
6
 */
7
8
#include "src/images/SkImageEncoderPriv.h"
9
10
#ifdef SK_ENCODE_WEBP
11
12
#include "include/core/SkBitmap.h"
13
#include "include/core/SkStream.h"
14
#include "include/core/SkUnPreMultiply.h"
15
#include "include/encode/SkWebpEncoder.h"
16
#include "include/private/SkColorData.h"
17
#include "include/private/SkImageInfoPriv.h"
18
#include "include/private/SkTemplates.h"
19
#include "src/images/SkImageEncoderFns.h"
20
#include "src/utils/SkUTF.h"
21
22
// A WebP encoder only, on top of (subset of) libwebp
23
// For more information on WebP image format, and libwebp library, see:
24
//   http://code.google.com/speed/webp/
25
//   http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
26
//   http://review.webmproject.org/gitweb?p=libwebp.git
27
28
#include <stdio.h>
29
extern "C" {
30
// If moving libwebp out of skia source tree, path for webp headers must be
31
// updated accordingly. Here, we enforce using local copy in webp sub-directory.
32
#include "webp/encode.h"
33
#include "webp/mux.h"
34
}
35
36
static int stream_writer(const uint8_t* data, size_t data_size,
37
27.1k
                         const WebPPicture* const picture) {
38
27.1k
  SkWStream* const stream = (SkWStream*)picture->custom_ptr;
39
27.1k
  return stream->write(data, data_size) ? 1 : 0;
40
27.1k
}
41
42
using WebPPictureImportProc = int (*) (WebPPicture* picture, const uint8_t* pixels, int stride);
43
44
4.29k
bool SkWebpEncoder::Encode(SkWStream* stream, const SkPixmap& pixmap, const Options& opts) {
45
4.29k
    if (!SkPixmapIsValid(pixmap)) {
46
0
        return false;
47
0
    }
48
49
4.29k
    if (SkColorTypeIsAlphaOnly(pixmap.colorType())) {
50
        // Maintain the existing behavior of not supporting encoding alpha-only images.
51
        // TODO: Support encoding alpha only to an image with alpha but no color?
52
0
        return false;
53
0
    }
54
55
4.29k
    if (nullptr == pixmap.addr()) {
56
0
        return false;
57
0
    }
58
59
4.29k
    WebPConfig webp_config;
60
4.29k
    if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, opts.fQuality)) {
61
1
        return false;
62
1
    }
63
64
4.28k
    WebPPicture pic;
65
4.28k
    WebPPictureInit(&pic);
66
4.28k
    SkAutoTCallVProc<WebPPicture, WebPPictureFree> autoPic(&pic);
67
4.28k
    pic.width = pixmap.width();
68
4.28k
    pic.height = pixmap.height();
69
4.28k
    pic.writer = stream_writer;
70
71
    // Set compression, method, and pixel format.
72
    // libwebp recommends using BGRA for lossless and YUV for lossy.
73
    // The choices of |webp_config.method| currently just match Chrome's defaults.  We
74
    // could potentially expose this decision to the client.
75
4.28k
    if (Compression::kLossy == opts.fCompression) {
76
2.53k
        webp_config.lossless = 0;
77
2.53k
#ifndef SK_WEBP_ENCODER_USE_DEFAULT_METHOD
78
2.53k
        webp_config.method = 3;
79
2.53k
#endif
80
2.53k
        pic.use_argb = 0;
81
1.75k
    } else {
82
1.75k
        webp_config.lossless = 1;
83
1.75k
        webp_config.method = 0;
84
1.75k
        pic.use_argb = 1;
85
1.75k
    }
86
87
    // If there is no need to embed an ICC profile, we write directly to the input stream.
88
    // Otherwise, we will first encode to |tmp| and use a mux to add the ICC chunk.  libwebp
89
    // forces us to have an encoded image before we can add a profile.
90
4.28k
    sk_sp<SkData> icc = icc_from_color_space(pixmap.info());
91
4.28k
    SkDynamicMemoryWStream tmp;
92
4.28k
    pic.custom_ptr = icc ? (void*)&tmp : (void*)stream;
93
94
4.28k
    {
95
4.28k
        const SkColorType ct = pixmap.colorType();
96
4.28k
        const bool premul = pixmap.alphaType() == kPremul_SkAlphaType;
97
98
4.28k
        SkBitmap tmpBm;
99
4.28k
        WebPPictureImportProc importProc = nullptr;
100
4.28k
        const SkPixmap* src = &pixmap;
101
4.28k
        if      (           ct ==  kRGB_888x_SkColorType) { importProc = WebPPictureImportRGBX; }
102
4.28k
        else if (!premul && ct == kRGBA_8888_SkColorType) { importProc = WebPPictureImportRGBA; }
103
#ifdef WebPPictureImportBGRA
104
        else if (!premul && ct == kBGRA_8888_SkColorType) { importProc = WebPPictureImportBGRA; }
105
#endif
106
4.28k
        else {
107
4.28k
            importProc = WebPPictureImportRGBA;
108
4.28k
            auto info = pixmap.info().makeColorType(kRGBA_8888_SkColorType)
109
4.28k
                                     .makeAlphaType(kUnpremul_SkAlphaType);
110
4.28k
            if (!tmpBm.tryAllocPixels(info)
111
4.28k
                    || !pixmap.readPixels(tmpBm.info(), tmpBm.getPixels(), tmpBm.rowBytes())) {
112
0
                return false;
113
0
            }
114
4.28k
            src = &tmpBm.pixmap();
115
4.28k
        }
116
117
4.28k
        if (!importProc(&pic, reinterpret_cast<const uint8_t*>(src->addr()), src->rowBytes())) {
118
0
            return false;
119
0
        }
120
4.28k
    }
121
122
4.28k
    if (!WebPEncode(&webp_config, &pic)) {
123
0
        return false;
124
0
    }
125
126
4.28k
    if (icc) {
127
0
        sk_sp<SkData> encodedData = tmp.detachAsData();
128
0
        WebPData encoded = { encodedData->bytes(), encodedData->size() };
129
0
        WebPData iccChunk = { icc->bytes(), icc->size() };
130
131
0
        SkAutoTCallVProc<WebPMux, WebPMuxDelete> mux(WebPMuxNew());
132
0
        if (WEBP_MUX_OK != WebPMuxSetImage(mux, &encoded, 0)) {
133
0
            return false;
134
0
        }
135
136
0
        if (WEBP_MUX_OK != WebPMuxSetChunk(mux, "ICCP", &iccChunk, 0)) {
137
0
            return false;
138
0
        }
139
140
0
        WebPData assembled;
141
0
        if (WEBP_MUX_OK != WebPMuxAssemble(mux, &assembled)) {
142
0
            return false;
143
0
        }
144
145
0
        stream->write(assembled.bytes, assembled.size);
146
0
        WebPDataClear(&assembled);
147
0
    }
148
149
4.28k
    return true;
150
4.28k
}
151
152
#endif