From 33e3741cad838d3228aeb110a107b021bf7b90a7 Mon Sep 17 00:00:00 2001 From: Matt Sarett Date: Wed, 21 Dec 2016 12:17:17 -0500 Subject: [PATCH] Decode images to sRGB, premultiply based on framework define This reenables color conversion to sRGB at decode time. Use the value ANDROID_LINEAR_BLENDING_ENABLED to decide whether to use the codec's linear premultiply or manually perform a legacy premultiply. Test: Demonstrated that legacy premultiply is still faster than the linear premultiply. So the performance of the two pass approach (decode, then premultiply) is acceptable. Skia tests both of these decoding modes. BUG:33741991 BUG:8860389 BUG:24279600 Change-Id: Idea0f359565bd8c7c3ba06e77a897173677db1c6 --- core/jni/Android.mk | 1 + core/jni/android/graphics/BitmapFactory.cpp | 52 +++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a13ebaf55cf4..252f168040df 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -215,6 +215,7 @@ LOCAL_C_INCLUDES += \ external/skia/src/effects \ external/skia/src/image \ external/skia/src/images \ + external/skia/src/utils \ external/sqlite/dist \ external/sqlite/android \ external/tremor/Tremor \ diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 1165a45c1535..19d4848e1656 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -8,6 +8,7 @@ #include "SkBRDAllocator.h" #include "SkFrontBufferedStream.h" #include "SkMath.h" +#include "SkOpts.h" #include "SkPixelRef.h" #include "SkStream.h" #include "SkUtils.h" @@ -224,6 +225,45 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); } +static inline SkAlphaType computeDecodeAlphaType(SkColorType colorType, SkAlphaType alphaType) { +#ifndef ANDROID_ENABLE_LINEAR_BLENDING + // Skia premultiplies linearly. Until the framework enables linear blending, + // it expects a legacy premultiply. + if (kPremul_SkAlphaType == alphaType && kRGBA_F16_SkColorType != colorType) { + return kUnpremul_SkAlphaType; + } +#endif + + return alphaType; +} + +static inline void premultiplyIfNecessary(SkBitmap* bitmap, SkPMColor* colorPtr, int* colorCount, + SkAlphaType alphaType, bool requireUnpremultiplied) { +#ifndef ANDROID_ENABLE_LINEAR_BLENDING + if (kUnpremul_SkAlphaType != alphaType || requireUnpremultiplied) { + return; + } + + switch (bitmap->colorType()) { + case kN32_SkColorType: + for (int y = 0; y < bitmap->height(); y++) { + SkOpts::RGBA_to_rgbA(bitmap->getAddr32(0, y), bitmap->getAddr32(0, y), + bitmap->width()); + } + + return; + case kIndex_8_SkColorType: + SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, *colorCount); + return; + default: + // kRGBA_F16 will be premultiplied by the codec if necessary. + // kGray_8 (alias kAlpha_8) and k565 are opaque. + LOG_ALWAYS_FATAL("Should be unreachable - no need for legacy premultiply."); + return; + } +#endif +} + static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) { // This function takes ownership of the input stream. Since the SkAndroidCodec // will take ownership of the stream, we don't necessarily need to take ownership @@ -391,13 +431,17 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding colorCount = &maxColors; } - // Set the alpha type for the decode. SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied); + SkAlphaType decodeAlphaType = computeDecodeAlphaType(decodeColorType, alphaType); const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), - decodeColorType, alphaType, GraphicsJNI::colorSpaceForType(decodeColorType)); + decodeColorType, decodeAlphaType, codec->computeOutputColorSpace(decodeColorType)); + + // When supported by the colorType, we will decode to sRGB (or linear sRGB). However, + // we only want to mark the bitmap as sRGB when linear blending is enabled. + SkImageInfo bitmapInfo = decodeInfo.makeAlphaType(alphaType) + .makeColorSpace(GraphicsJNI::colorSpaceForType(decodeColorType)); - SkImageInfo bitmapInfo = decodeInfo; if (decodeColorType == kGray_8_SkColorType) { // The legacy implementation of BitmapFactory used kAlpha8 for // grayscale images (before kGray8 existed). While the codec @@ -433,6 +477,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding default: return nullObjectReturn("codec->getAndroidPixels() failed."); } + premultiplyIfNecessary(&decodingBitmap, colorPtr, colorCount, decodeAlphaType, + requireUnpremultiplied); jbyteArray ninePatchChunk = NULL; if (peeker.mPatch != NULL) { -- 2.11.0