From 55213562f9a63cbc324833fdd1c16cc79646515a Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Mon, 23 Jan 2017 19:37:37 -0500 Subject: [PATCH] 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 Reviewed-by: Leon Scroggins --- gm/encode-srgb.cpp | 2 +- src/images/SkImageEncoderPriv.h | 1 + src/images/SkWEBPImageEncoder.cpp | 86 +++++++++++++++++++++++++++++---------- src/images/transform_scanline.h | 31 +++++++++++++- 4 files changed, 95 insertions(+), 25 deletions(-) diff --git a/gm/encode-srgb.cpp b/gm/encode-srgb.cpp index 4a126df..eae1a6d 100644 --- a/gm/encode-srgb.cpp +++ b/gm/encode-srgb.cpp @@ -120,7 +120,7 @@ static sk_sp 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; diff --git a/src/images/SkImageEncoderPriv.h b/src/images/SkImageEncoderPriv.h index 7748204..e2f72ca 100644 --- a/src/images/SkImageEncoderPriv.h +++ b/src/images/SkImageEncoderPriv.h @@ -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 diff --git a/src/images/SkWEBPImageEncoder.cpp b/src/images/SkWEBPImageEncoder.cpp index 7d95906..5928f97 100644 --- a/src/images/SkWEBPImageEncoder.cpp +++ b/src/images/SkWEBPImageEncoder.cpp @@ -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 diff --git a/src/images/transform_scanline.h b/src/images/transform_scanline.h index d492036..6bf3474 100644 --- a/src/images/transform_scanline.h +++ b/src/images/transform_scanline.h @@ -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); +} -- 2.7.4