Flutter Engine
The Flutter Engine
SkWebpEncoderImpl.cpp
Go to the documentation of this file.
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
9
13#include "include/core/SkData.h"
17#include "include/core/SkSpan.h"
25
26#include <cstddef>
27#include <cstdint>
28#include <memory>
29
30class GrDirectContext;
31class SkImage;
32
33// A WebP encoder only, on top of (subset of) libwebp
34// For more information on WebP image format, and libwebp library, see:
35// http://code.google.com/speed/webp/
36// http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
37// http://review.webmproject.org/gitweb?p=libwebp.git
38
39extern "C" {
40// If moving libwebp out of skia source tree, path for webp headers must be
41// updated accordingly. Here, we enforce using local copy in webp sub-directory.
42#include "webp/encode.h" // NO_G3_REWRITE
43#include "webp/mux.h" // NO_G3_REWRITE
44#include "webp/mux_types.h" // NO_G3_REWRITE
45}
46
47static int stream_writer(const uint8_t* data, size_t data_size, const WebPPicture* const picture) {
48 SkWStream* const stream = (SkWStream*)picture->custom_ptr;
49 return stream->write(data, data_size) ? 1 : 0;
50}
51
52using WebPPictureImportProc = int (*)(WebPPicture* picture, const uint8_t* pixels, int stride);
53
54static bool preprocess_webp_picture(WebPPicture* pic,
55 WebPConfig* webp_config,
56 const SkPixmap& pixmap,
57 const SkWebpEncoder::Options& opts) {
58 if (!SkPixmapIsValid(pixmap)) {
59 return false;
60 }
61
62 if (SkColorTypeIsAlphaOnly(pixmap.colorType())) {
63 // Maintain the existing behavior of not supporting encoding alpha-only images.
64 // TODO: Support encoding alpha only to an image with alpha but no color?
65 return false;
66 }
67
68 if (nullptr == pixmap.addr()) {
69 return false;
70 }
71
72 pic->width = pixmap.width();
73 pic->height = pixmap.height();
74
75 // Set compression, method, and pixel format.
76 // libwebp recommends using BGRA for lossless and YUV for lossy.
77 // The choices of |webp_config.method| currently just match Chrome's defaults. We
78 // could potentially expose this decision to the client.
80 webp_config->lossless = 0;
81#ifndef SK_WEBP_ENCODER_USE_DEFAULT_METHOD
82 webp_config->method = 3;
83#endif
84 pic->use_argb = 0;
85 } else {
86 webp_config->lossless = 1;
87 webp_config->method = 0;
88 pic->use_argb = 1;
89 }
90
91 {
92 const SkColorType ct = pixmap.colorType();
93 const bool premul = pixmap.alphaType() == kPremul_SkAlphaType;
94
95 SkBitmap tmpBm;
96 WebPPictureImportProc importProc = nullptr;
97 const SkPixmap* src = &pixmap;
98 if (ct == kRGB_888x_SkColorType) {
99 importProc = WebPPictureImportRGBX;
100 } else if (!premul && ct == kRGBA_8888_SkColorType) {
101 importProc = WebPPictureImportRGBA;
102 }
103#ifdef WebPPictureImportBGRA
104 else if (!premul && ct == kBGRA_8888_SkColorType) {
105 importProc = WebPPictureImportBGRA;
106 }
107#endif
108 else {
109 importProc = WebPPictureImportRGBA;
110 auto info = pixmap.info()
113 if (!tmpBm.tryAllocPixels(info) ||
114 !pixmap.readPixels(tmpBm.info(), tmpBm.getPixels(), tmpBm.rowBytes())) {
115 return false;
116 }
117 src = &tmpBm.pixmap();
118 }
119
120 if (!importProc(pic, reinterpret_cast<const uint8_t*>(src->addr()), src->rowBytes())) {
121 return false;
122 }
123 }
124
125 return true;
126}
127
128namespace SkWebpEncoder {
129
130bool Encode(SkWStream* stream, const SkPixmap& pixmap, const Options& opts) {
131 if (!stream) {
132 return false;
133 }
134
135 WebPConfig webp_config;
136 if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, opts.fQuality)) {
137 return false;
138 }
139
140 WebPPicture pic;
141 if (!WebPPictureInit(&pic)) {
142 return false;
143 }
145
146 if (!preprocess_webp_picture(&pic, &webp_config, pixmap, opts)) {
147 return false;
148 }
149
150 // If there is no need to embed an ICC profile, we write directly to the input stream.
151 // Otherwise, we will first encode to |tmp| and use a mux to add the ICC chunk. libwebp
152 // forces us to have an encoded image before we can add a profile.
153 sk_sp<SkData> icc =
154 icc_from_color_space(pixmap.info(), opts.fICCProfile, opts.fICCProfileDescription);
156 pic.custom_ptr = icc ? (void*)&tmp : (void*)stream;
157 pic.writer = stream_writer;
158
159 if (!WebPEncode(&webp_config, &pic)) {
160 return false;
161 }
162
163 if (icc) {
164 sk_sp<SkData> encodedData = tmp.detachAsData();
165 WebPData encoded = {encodedData->bytes(), encodedData->size()};
166 WebPData iccChunk = {icc->bytes(), icc->size()};
167
169 if (WEBP_MUX_OK != WebPMuxSetImage(mux, &encoded, 0)) {
170 return false;
171 }
172
173 if (WEBP_MUX_OK != WebPMuxSetChunk(mux, "ICCP", &iccChunk, 0)) {
174 return false;
175 }
176
177 WebPData assembled;
178 SkAutoTCallVProc<WebPData, WebPDataClear> autoWebPData(&assembled);
179 if (WEBP_MUX_OK != WebPMuxAssemble(mux, &assembled)) {
180 return false;
181 }
182
183 if (!stream->write(assembled.bytes, assembled.size)) {
184 return false;
185 }
186 }
187
188 return true;
189}
190
192 if (!stream || frames.empty()) {
193 return false;
194 }
195
196 const int canvasWidth = frames.front().pixmap.width();
197 const int canvasHeight = frames.front().pixmap.height();
198 int timestamp = 0;
199
200 std::unique_ptr<WebPAnimEncoder, void (*)(WebPAnimEncoder*)> enc(
201 WebPAnimEncoderNew(canvasWidth, canvasHeight, nullptr), WebPAnimEncoderDelete);
202 if (!enc) {
203 return false;
204 }
205
206 for (const auto& frame : frames) {
207 const auto& pixmap = frame.pixmap;
208
209 if (pixmap.width() != canvasWidth || pixmap.height() != canvasHeight) {
210 return false;
211 }
212
213 WebPConfig webp_config;
214 if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, opts.fQuality)) {
215 return false;
216 }
217
218 WebPPicture pic;
219 if (!WebPPictureInit(&pic)) {
220 return false;
221 }
223
224 if (!preprocess_webp_picture(&pic, &webp_config, pixmap, opts)) {
225 return false;
226 }
227
228 if (!WebPEncode(&webp_config, &pic)) {
229 return false;
230 }
231
232 if (!WebPAnimEncoderAdd(enc.get(), &pic, timestamp, &webp_config)) {
233 return false;
234 }
235
236 timestamp += frame.duration;
237 }
238
239 // Add a last fake frame to signal the last duration.
240 if (!WebPAnimEncoderAdd(enc.get(), nullptr, timestamp, nullptr)) {
241 return false;
242 }
243
244 WebPData assembled;
245 SkAutoTCallVProc<WebPData, WebPDataClear> autoWebPData(&assembled);
246 if (!WebPAnimEncoderAssemble(enc.get(), &assembled)) {
247 return false;
248 }
249
250 enc.reset();
251
252 return stream->write(assembled.bytes, assembled.size);
253}
254
255sk_sp<SkData> Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) {
256 if (!img) {
257 return nullptr;
258 }
259 SkBitmap bm;
260 if (!as_IB(img)->getROPixels(ctx, &bm)) {
261 return nullptr;
262 }
264 if (Encode(&stream, bm.pixmap(), options)) {
265 return stream.detachAsData();
266 }
267 return nullptr;
268}
269
270} // namespace SkWebpEncoder
const char * options
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
SkColorType
Definition: SkColorType.h:19
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
static sk_sp< SkData > icc_from_color_space(const SkColorSpace *cs, const skcms_ICCProfile *profile, const char *profile_description)
static bool SkPixmapIsValid(const SkPixmap &src)
static bool SkColorTypeIsAlphaOnly(SkColorType ct)
static SkImage_Base * as_IB(SkImage *image)
Definition: SkImage_Base.h:201
static int stream_writer(const uint8_t *data, size_t data_size, const WebPPicture *const picture)
static bool preprocess_webp_picture(WebPPicture *pic, WebPConfig *webp_config, const SkPixmap &pixmap, const SkWebpEncoder::Options &opts)
int(*)(WebPPicture *picture, const uint8_t *pixels, int stride) WebPPictureImportProc
static uint32_t premul(uint32_t color)
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
size_t rowBytes() const
Definition: SkBitmap.h:238
void * getPixels() const
Definition: SkBitmap.h:283
const SkImageInfo & info() const
Definition: SkBitmap.h:139
bool tryAllocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:271
const uint8_t * bytes() const
Definition: SkData.h:43
size_t size() const
Definition: SkData.h:30
sk_sp< SkData > detachAsData()
Definition: SkStream.cpp:707
int width() const
Definition: SkPixmap.h:160
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes) const
Definition: SkPixmap.h:592
SkColorType colorType() const
Definition: SkPixmap.h:173
const SkImageInfo & info() const
Definition: SkPixmap.h:135
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
SkAlphaType alphaType() const
Definition: SkPixmap.h:175
constexpr T & front() const
Definition: SkSpan_impl.h:88
constexpr bool empty() const
Definition: SkSpan_impl.h:96
double frame
Definition: examples.cpp:31
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
SK_API bool EncodeAnimated(SkWStream *dst, SkSpan< const SkEncoder::Frame > src, const Options &options)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466
SkImageInfo makeColorType(SkColorType newColorType) const
Definition: SkImageInfo.h:475
Compression fCompression
Definition: SkWebpEncoder.h:43
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63