blob: 07b8fa018e42e5efde8386dbaf6e4c1bfb960339 [file] [log] [blame]
commit-bot@chromium.orga936e372013-03-14 14:42:18 +00001/*
Leon Scroggins III20baaee2020-03-09 11:48:03 -04002 * Copyright 2010 The Android Open Source Project
commit-bot@chromium.orga936e372013-03-14 14:42:18 +00003 *
Leon Scroggins III20baaee2020-03-09 11:48:03 -04004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
commit-bot@chromium.orga936e372013-03-14 14:42:18 +00006 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/images/SkImageEncoderPriv.h"
Hal Canary1fcc4042016-11-30 17:07:59 -05009
Leon Scroggins IIIa77f30c2020-03-09 14:23:30 -040010#ifdef SK_ENCODE_WEBP
Mike Kleinab737e42019-05-15 21:58:15 +000011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#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"
Leon Scroggins III1adcac52020-05-28 17:12:59 -040017#include "include/private/SkImageInfoPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "include/private/SkTemplates.h"
19#include "src/images/SkImageEncoderFns.h"
20#include "src/utils/SkUTF.h"
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000021
Matt Sarett46a45ba2017-04-06 20:34:38 +000022// A WebP encoder only, on top of (subset of) libwebp
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000023// 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>
29extern "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.
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000032#include "webp/encode.h"
Matt Sarett46a45ba2017-04-06 20:34:38 +000033#include "webp/mux.h"
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000034}
35
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000036static int stream_writer(const uint8_t* data, size_t data_size,
37 const WebPPicture* const picture) {
38 SkWStream* const stream = (SkWStream*)picture->custom_ptr;
39 return stream->write(data, data_size) ? 1 : 0;
40}
41
Leon Scroggins III1adcac52020-05-28 17:12:59 -040042using WebPPictureImportProc = int (*) (WebPPicture* picture, const uint8_t* pixels, int stride);
43
Matt Sarettd5a16912017-05-16 17:06:52 -040044bool SkWebpEncoder::Encode(SkWStream* stream, const SkPixmap& pixmap, const Options& opts) {
Brian Osmane1adc3a2018-06-04 09:21:17 -040045 if (!SkPixmapIsValid(pixmap)) {
Matt Sarett04c37312017-05-05 14:02:13 -040046 return false;
Matt Sarett55213562017-01-23 19:37:37 -050047 }
48
Leon Scroggins III1adcac52020-05-28 17:12:59 -040049 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?
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000052 return false;
53 }
Matt Sarett55213562017-01-23 19:37:37 -050054
Hal Canary1fcc4042016-11-30 17:07:59 -050055 if (nullptr == pixmap.addr()) {
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000056 return false;
57 }
58
59 WebPConfig webp_config;
Matt Sarett04c37312017-05-05 14:02:13 -040060 if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, opts.fQuality)) {
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000061 return false;
62 }
63
64 WebPPicture pic;
65 WebPPictureInit(&pic);
Matt Sarett46a45ba2017-04-06 20:34:38 +000066 SkAutoTCallVProc<WebPPicture, WebPPictureFree> autoPic(&pic);
Hal Canary1fcc4042016-11-30 17:07:59 -050067 pic.width = pixmap.width();
68 pic.height = pixmap.height();
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000069 pic.writer = stream_writer;
Matt Sarett46a45ba2017-04-06 20:34:38 +000070
Matt Sarett2f687872017-05-19 19:12:54 -040071 // 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 if (Compression::kLossy == opts.fCompression) {
76 webp_config.lossless = 0;
77#ifndef SK_WEBP_ENCODER_USE_DEFAULT_METHOD
78 webp_config.method = 3;
79#endif
80 pic.use_argb = 0;
81 } else {
82 webp_config.lossless = 1;
83 webp_config.method = 0;
84 pic.use_argb = 1;
85 }
86
Matt Sarett46a45ba2017-04-06 20:34:38 +000087 // 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.
Matt Sarett1950e0a2017-06-12 16:17:30 -040090 sk_sp<SkData> icc = icc_from_color_space(pixmap.info());
Matt Sarett46a45ba2017-04-06 20:34:38 +000091 SkDynamicMemoryWStream tmp;
92 pic.custom_ptr = icc ? (void*)&tmp : (void*)stream;
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000093
Leon Scroggins III1adcac52020-05-28 17:12:59 -040094 {
95 const SkColorType ct = pixmap.colorType();
96 const bool premul = pixmap.alphaType() == kPremul_SkAlphaType;
commit-bot@chromium.orga936e372013-03-14 14:42:18 +000097
Leon Scroggins III1adcac52020-05-28 17:12:59 -040098 SkBitmap tmpBm;
99 WebPPictureImportProc importProc = nullptr;
100 const SkPixmap* src = &pixmap;
101 if ( ct == kRGB_888x_SkColorType) { importProc = WebPPictureImportRGBX; }
102 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 else {
Matt Sarett46a45ba2017-04-06 20:34:38 +0000107 importProc = WebPPictureImportRGBA;
Leon Scroggins III1adcac52020-05-28 17:12:59 -0400108 auto info = pixmap.info().makeColorType(kRGBA_8888_SkColorType)
109 .makeAlphaType(kUnpremul_SkAlphaType);
110 if (!tmpBm.tryAllocPixels(info)
111 || !pixmap.readPixels(tmpBm.info(), tmpBm.getPixels(), tmpBm.rowBytes())) {
112 return false;
113 }
114 src = &tmpBm.pixmap();
Matt Sarett55213562017-01-23 19:37:37 -0500115 }
commit-bot@chromium.orga936e372013-03-14 14:42:18 +0000116
Leon Scroggins III1adcac52020-05-28 17:12:59 -0400117 if (!importProc(&pic, reinterpret_cast<const uint8_t*>(src->addr()), src->rowBytes())) {
118 return false;
119 }
Matt Sarett46a45ba2017-04-06 20:34:38 +0000120 }
commit-bot@chromium.orga936e372013-03-14 14:42:18 +0000121
Matt Sarett46a45ba2017-04-06 20:34:38 +0000122 if (!WebPEncode(&webp_config, &pic)) {
123 return false;
124 }
125
126 if (icc) {
127 sk_sp<SkData> encodedData = tmp.detachAsData();
128 WebPData encoded = { encodedData->bytes(), encodedData->size() };
129 WebPData iccChunk = { icc->bytes(), icc->size() };
130
131 SkAutoTCallVProc<WebPMux, WebPMuxDelete> mux(WebPMuxNew());
132 if (WEBP_MUX_OK != WebPMuxSetImage(mux, &encoded, 0)) {
133 return false;
134 }
135
136 if (WEBP_MUX_OK != WebPMuxSetChunk(mux, "ICCP", &iccChunk, 0)) {
137 return false;
138 }
139
140 WebPData assembled;
141 if (WEBP_MUX_OK != WebPMuxAssemble(mux, &assembled)) {
142 return false;
143 }
144
145 stream->write(assembled.bytes, assembled.size);
146 WebPDataClear(&assembled);
147 }
148
149 return true;
commit-bot@chromium.orga936e372013-03-14 14:42:18 +0000150}
Mike Kleinab737e42019-05-15 21:58:15 +0000151
152#endif