Add F16 and gamma correct support to webp encoder

BUG=skia:

Change-Id: Ib788466fa1e2bed26e7ffd8f03bee42930eae1d6
Reviewed-on: https://skia-review.googlesource.com/7425
Commit-Queue: Matt Sarett <msarett@google.com>
Reviewed-by: Leon Scroggins <scroggo@google.com>
This commit is contained in:
Matt Sarett 2017-01-23 19:37:37 -05:00 committed by Skia Commit-Bot
parent 6f4a9b2948
commit 55213562f9
4 changed files with 95 additions and 25 deletions

View File

@ -120,7 +120,7 @@ static sk_sp<SkData> encode_data(const SkBitmap& bitmap, SkEncodedImageFormat fo
SkEncodeImageAsPNG(&buf, src, options);
break;
case SkEncodedImageFormat::kWEBP:
SkEncodeImage(&buf, src, SkEncodedImageFormat::kWEBP, 100);
SkEncodeImageAsWEBP(&buf, src, options);
break;
default:
break;

View File

@ -35,6 +35,7 @@ struct SkEncodeOptions {
#endif
#ifdef SK_HAS_WEBP_LIBRARY
bool SkEncodeImageAsWEBP(SkWStream*, const SkPixmap&, const SkEncodeOptions&);
bool SkEncodeImageAsWEBP(SkWStream*, const SkPixmap&, int quality);
#else
#define SkEncodeImageAsWEBP(...) false

View File

@ -39,46 +39,44 @@ extern "C" {
#include "webp/encode.h"
}
static transform_scanline_proc choose_proc(const SkImageInfo& info, int* bpp) {
static transform_scanline_proc choose_proc(const SkImageInfo& info) {
const bool isGammaEncoded = info.gammaCloseToSRGB();
switch (info.colorType()) {
case kRGBA_8888_SkColorType:
switch (info.alphaType()) {
case kOpaque_SkAlphaType:
*bpp = 3;
return transform_scanline_RGBX;
case kUnpremul_SkAlphaType:
*bpp = 4;
return transform_scanline_memcpy;
case kPremul_SkAlphaType:
*bpp = 4;
return transform_scanline_rgbA;
return isGammaEncoded ? transform_scanline_srgbA :
transform_scanline_rgbA;
default:
return nullptr;
}
case kBGRA_8888_SkColorType:
switch (info.alphaType()) {
case kOpaque_SkAlphaType:
*bpp = 3;
return transform_scanline_BGRX;
case kUnpremul_SkAlphaType:
*bpp = 4;
return transform_scanline_BGRA;
case kPremul_SkAlphaType:
*bpp = 4;
return transform_scanline_bgrA;
return isGammaEncoded ? transform_scanline_sbgrA :
transform_scanline_bgrA;
default:
return nullptr;
}
case kRGB_565_SkColorType:
*bpp = 3;
if (!info.isOpaque()) {
return nullptr;
}
return transform_scanline_565;
case kARGB_4444_SkColorType:
switch (info.alphaType()) {
case kOpaque_SkAlphaType:
*bpp = 3;
return transform_scanline_444;
case kPremul_SkAlphaType:
*bpp = 4;
return transform_scanline_4444;
default:
return nullptr;
@ -86,20 +84,31 @@ static transform_scanline_proc choose_proc(const SkImageInfo& info, int* bpp) {
case kIndex_8_SkColorType:
switch (info.alphaType()) {
case kOpaque_SkAlphaType:
*bpp = 3;
return transform_scanline_index8_opaque;
case kUnpremul_SkAlphaType:
case kPremul_SkAlphaType:
// If the color table is premultiplied, we'll fix it before calling the
// scanline proc.
*bpp = 4;
return transform_scanline_index8_unpremul;
default:
return nullptr;
}
case kGray_8_SkColorType:
*bpp = 3;
return transform_scanline_gray;
case kRGBA_F16_SkColorType:
if (!info.colorSpace() || !info.colorSpace()->gammaIsLinear()) {
return nullptr;
}
switch (info.alphaType()) {
case kOpaque_SkAlphaType:
case kUnpremul_SkAlphaType:
return transform_scanline_F16_to_8888;
case kPremul_SkAlphaType:
return transform_scanline_F16_premul_to_8888;
default:
return nullptr;
}
default:
return nullptr;
}
@ -111,13 +120,31 @@ static int stream_writer(const uint8_t* data, size_t data_size,
return stream->write(data, data_size) ? 1 : 0;
}
bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& pixmap, int quality) {
int bpp = -1;
const transform_scanline_proc proc = choose_proc(pixmap.info(), &bpp);
static bool do_encode(SkWStream* stream, const SkPixmap& srcPixmap, const SkEncodeOptions& opts,
int quality) {
SkASSERT(!srcPixmap.colorSpace() || srcPixmap.colorSpace()->gammaCloseToSRGB() ||
srcPixmap.colorSpace()->gammaIsLinear());
SkPixmap pixmap = srcPixmap;
if (SkEncodeOptions::PremulBehavior::kLegacy == opts.fPremulBehavior) {
pixmap.setColorSpace(nullptr);
} else {
if (!pixmap.colorSpace()) {
return false;
}
}
const transform_scanline_proc proc = choose_proc(pixmap.info());
if (!proc) {
return false;
}
SkASSERT(-1 != bpp);
int bpp;
if (kRGBA_F16_SkColorType == pixmap.colorType()) {
bpp = 4;
} else {
bpp = pixmap.isOpaque() ? 3 : 4;
}
if (nullptr == pixmap.addr()) {
return false;
@ -132,8 +159,10 @@ bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& pixmap, int quality)
colors = pixmap.ctable()->readColors();
if (kPremul_SkAlphaType == pixmap.alphaType()) {
transform_scanline_rgbA((char*) storage, (const char*) colors, pixmap.ctable()->count(),
4, nullptr);
// Unpremultiply the colors.
const SkImageInfo rgbaInfo = pixmap.info().makeColorType(kRGBA_8888_SkColorType);
transform_scanline_proc proc = choose_proc(rgbaInfo);
proc((char*) storage, (const char*) colors, pixmap.ctable()->count(), 4, nullptr);
colors = storage;
}
}
@ -165,7 +194,11 @@ bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& pixmap, int quality)
if (bpp == 3) {
ok = SkToBool(WebPPictureImportRGB(&pic, &rgb[0], rgbStride));
} else {
ok = SkToBool(WebPPictureImportRGBA(&pic, &rgb[0], rgbStride));
if (pixmap.isOpaque()) {
ok = SkToBool(WebPPictureImportRGBX(&pic, &rgb[0], rgbStride));
} else {
ok = SkToBool(WebPPictureImportRGBA(&pic, &rgb[0], rgbStride));
}
}
ok = ok && WebPEncode(&webp_config, &pic);
@ -173,4 +206,13 @@ bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& pixmap, int quality)
return ok;
}
bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& src, int quality) {
return do_encode(stream, src, SkEncodeOptions(), quality);
}
bool SkEncodeImageAsWEBP(SkWStream* stream, const SkPixmap& src, const SkEncodeOptions& opts) {
return do_encode(stream, src, opts, 100);
}
#endif

View File

@ -254,7 +254,7 @@ static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK
}
/**
* Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
* Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
*/
static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
int width, int, const SkPMColor*) {
@ -266,7 +266,7 @@ static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_
}
/**
* Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
* Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
*/
static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
int width, int, const SkPMColor*) {
@ -277,3 +277,30 @@ static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const ch
p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
p.run(0, width);
}
/**
* Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
*/
static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
const char* SK_RESTRICT src, int width, int,
const SkPMColor*) {
SkRasterPipeline p;
p.append(SkRasterPipeline::load_f16, (const void**) &src);
p.append(SkRasterPipeline::to_srgb);
p.append(SkRasterPipeline::store_8888, (void**) &dst);
p.run(0, width);
}
/**
* Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
*/
static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
const char* SK_RESTRICT src, int width,
int, const SkPMColor*) {
SkRasterPipeline p;
p.append(SkRasterPipeline::load_f16, (const void**) &src);
p.append(SkRasterPipeline::unpremul);
p.append(SkRasterPipeline::to_srgb);
p.append(SkRasterPipeline::store_8888, (void**) &dst);
p.run(0, width);
}