Merge "Add BitmapFactory.Options.inColorSpace" into oc-dev

This commit is contained in:
Romain Guy
2017-04-14 21:08:34 +00:00
committed by Android (Google) Code Review
11 changed files with 344 additions and 224 deletions

View File

@ -12533,6 +12533,7 @@ package android.graphics {
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;

View File

@ -13303,6 +13303,7 @@ package android.graphics {
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;

View File

@ -12575,6 +12575,7 @@ package android.graphics {
field public boolean inJustDecodeBounds;
field public boolean inMutable;
field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.ColorSpace inPreferredColorSpace;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;

View File

@ -44,14 +44,6 @@ static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_reinitMethodID;
static jmethodID gBitmap_getAllocationByteCountMethodID;
static jfieldID gTransferParams_aFieldID;
static jfieldID gTransferParams_bFieldID;
static jfieldID gTransferParams_cFieldID;
static jfieldID gTransferParams_dFieldID;
static jfieldID gTransferParams_eFieldID;
static jfieldID gTransferParams_fFieldID;
static jfieldID gTransferParams_gFieldID;
namespace android {
class BitmapWrapper {
@ -742,28 +734,8 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
if (colorType != kN32_SkColorType || xyzD50 == nullptr || transferParameters == nullptr) {
colorSpace = GraphicsJNI::colorSpaceForType(colorType);
} else {
SkColorSpaceTransferFn p;
p.fA = (float) env->GetDoubleField(transferParameters, gTransferParams_aFieldID);
p.fB = (float) env->GetDoubleField(transferParameters, gTransferParams_bFieldID);
p.fC = (float) env->GetDoubleField(transferParameters, gTransferParams_cFieldID);
p.fD = (float) env->GetDoubleField(transferParameters, gTransferParams_dFieldID);
p.fE = (float) env->GetDoubleField(transferParameters, gTransferParams_eFieldID);
p.fF = (float) env->GetDoubleField(transferParameters, gTransferParams_fFieldID);
p.fG = (float) env->GetDoubleField(transferParameters, gTransferParams_gFieldID);
SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
xyzMatrix.setFloat(0, 0, array[0]);
xyzMatrix.setFloat(1, 0, array[1]);
xyzMatrix.setFloat(2, 0, array[2]);
xyzMatrix.setFloat(0, 1, array[3]);
xyzMatrix.setFloat(1, 1, array[4]);
xyzMatrix.setFloat(2, 1, array[5]);
xyzMatrix.setFloat(0, 2, array[6]);
xyzMatrix.setFloat(1, 2, array[7]);
xyzMatrix.setFloat(2, 2, array[8]);
env->ReleaseFloatArrayElements(xyzD50, array, 0);
SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
}
@ -1635,20 +1607,6 @@ static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlon
}
///////////////////////////////////////////////////////////////////////////////
static jclass make_globalref(JNIEnv* env, const char classname[])
{
jclass c = env->FindClass(classname);
SkASSERT(c);
return (jclass) env->NewGlobalRef(c);
}
static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
const char fieldname[], const char type[])
{
jfieldID id = env->GetFieldID(clazz, fieldname, type);
SkASSERT(id);
return id;
}
static const JNINativeMethod gBitmapMethods[] = {
{ "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;",
@ -1706,20 +1664,11 @@ static const JNINativeMethod gBitmapMethods[] = {
int register_android_graphics_Bitmap(JNIEnv* env)
{
jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
gBitmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap"));
gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
}

View File

@ -27,6 +27,7 @@
jfieldID gOptions_justBoundsFieldID;
jfieldID gOptions_sampleSizeFieldID;
jfieldID gOptions_configFieldID;
jfieldID gOptions_colorSpaceFieldID;
jfieldID gOptions_premultipliedFieldID;
jfieldID gOptions_mutableFieldID;
jfieldID gOptions_ditherFieldID;
@ -51,20 +52,6 @@ jmethodID gInsetStruct_constructorMethodID;
jclass gBitmapConfig_class;
jmethodID gBitmapConfig_nativeToConfigMethodID;
jclass gColorSpace_class;
jmethodID gColorSpace_getMethodID;
jmethodID gColorSpace_matchMethodID;
jclass gColorSpaceRGB_class;
jmethodID gColorSpaceRGB_constructorMethodID;
jclass gColorSpace_Named_class;
jfieldID gColorSpace_Named_sRGBFieldID;
jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
jclass gTransferParameters_class;
jmethodID gTransferParameters_constructorMethodID;
using namespace android;
jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) {
@ -243,70 +230,6 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
}
static jobject getColorSpace(JNIEnv* env,
sk_sp<SkColorSpace>& decodeColorSpace, SkColorType decodeColorType) {
jobject colorSpace = nullptr;
// No need to match, we know what the output color space will be
if (decodeColorType == kRGBA_F16_SkColorType) {
jobject linearExtendedSRGB = env->GetStaticObjectField(
gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_getMethodID, linearExtendedSRGB);
} else {
// Same here, no need to match
if (decodeColorSpace->isSRGB()) {
jobject sRGB = env->GetStaticObjectField(
gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_getMethodID, sRGB);
} else if (decodeColorSpace.get() != nullptr) {
// Try to match against known RGB color spaces using the CIE XYZ D50
// conversion matrix and numerical transfer function parameters
SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
SkColorSpaceTransferFn transferParams;
// We can only handle numerical transfer functions at the moment
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
jobject params = env->NewObject(gTransferParameters_class,
gTransferParameters_constructorMethodID,
transferParams.fA, transferParams.fB, transferParams.fC,
transferParams.fD, transferParams.fE, transferParams.fF,
transferParams.fG);
jfloatArray xyzArray = env->NewFloatArray(9);
jfloat xyz[9] = {
xyzMatrix.getFloat(0, 0),
xyzMatrix.getFloat(1, 0),
xyzMatrix.getFloat(2, 0),
xyzMatrix.getFloat(0, 1),
xyzMatrix.getFloat(1, 1),
xyzMatrix.getFloat(2, 1),
xyzMatrix.getFloat(0, 2),
xyzMatrix.getFloat(1, 2),
xyzMatrix.getFloat(2, 2)
};
env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_matchMethodID, xyzArray, params);
if (colorSpace == nullptr) {
// We couldn't find an exact match, let's create a new color space
// instance with the 3x3 conversion matrix and transfer function
colorSpace = env->NewObject(gColorSpaceRGB_class,
gColorSpaceRGB_constructorMethodID,
env->NewStringUTF("Unknown"), xyzArray, params);
}
env->DeleteLocalRef(xyzArray);
}
}
return colorSpace;
}
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
@ -323,6 +246,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
float scale = 1.0f;
bool requireUnpremultiplied = false;
jobject javaBitmap = NULL;
sk_sp<SkColorSpace> prefColorSpace = nullptr;
// Update with options supplied by the client.
if (options != NULL) {
@ -346,6 +270,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
@ -399,7 +325,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
// Set the decode colorType
SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);
sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(decodeColorType);
sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(
decodeColorType, prefColorSpace);
// Set the options and return if the client only wants the size.
if (options != NULL) {
@ -427,7 +354,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
env->SetObjectField(options, gOptions_outConfigFieldID, config);
env->SetObjectField(options, gOptions_outColorSpaceFieldID,
getColorSpace(env, decodeColorSpace, decodeColorType));
GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
if (onlyDecodeSize) {
return nullptr;
@ -795,6 +722,8 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I");
gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig",
"Landroid/graphics/Bitmap$Config;");
gOptions_colorSpaceFieldID = GetFieldIDOrDie(env, options_class, "inPreferredColorSpace",
"Landroid/graphics/ColorSpace;");
gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z");
gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z");
gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z");
@ -827,29 +756,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
"nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;");
gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
"get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
"([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;");
gColorSpaceRGB_class = MakeGlobalRefOrDie(env,
FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
"<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
gColorSpace_Named_class = MakeGlobalRefOrDie(env,
FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
"android/graphics/ColorSpace$Rgb$TransferParameters"));
gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
"<init>", "(DDDDDDD)V");
return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
gMethods, NELEM(gMethods));
}

View File

@ -8,6 +8,7 @@ extern jclass gOptions_class;
extern jfieldID gOptions_justBoundsFieldID;
extern jfieldID gOptions_sampleSizeFieldID;
extern jfieldID gOptions_configFieldID;
extern jfieldID gOptions_colorSpaceFieldID;
extern jfieldID gOptions_premultipliedFieldID;
extern jfieldID gOptions_ditherFieldID;
extern jfieldID gOptions_purgeableFieldID;
@ -17,9 +18,14 @@ extern jfieldID gOptions_preferQualityOverSpeedFieldID;
extern jfieldID gOptions_widthFieldID;
extern jfieldID gOptions_heightFieldID;
extern jfieldID gOptions_mimeFieldID;
extern jfieldID gOptions_outConfigFieldID;
extern jfieldID gOptions_outColorSpaceFieldID;
extern jfieldID gOptions_mCancelID;
extern jfieldID gOptions_bitmapFieldID;
extern jclass gBitmapConfig_class;
extern jmethodID gBitmapConfig_nativeToConfigMethodID;
jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format);
jobject decodeBitmap(JNIEnv* env, void* data, size_t size);

View File

@ -132,11 +132,14 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
bool requireUnpremul = false;
jobject javaBitmap = NULL;
bool isHardware = false;
sk_sp<SkColorSpace> colorSpace = nullptr;
// Update the default options with any options supplied by the client.
if (NULL != options) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
@ -148,8 +151,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
env->SetIntField(options, gOptions_widthFieldID, -1);
env->SetIntField(options, gOptions_heightFieldID, -1);
env->SetObjectField(options, gOptions_mimeFieldID, 0);
env->SetObjectField(options, gOptions_outConfigFieldID, 0);
env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
}
SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
SkColorType decodeColorType = brd->computeOutputColorType(colorType);
sk_sp<SkColorSpace> decodeColorSpace = brd->computeOutputColorSpace(
decodeColorType, colorSpace);
// Recycle a bitmap if possible.
android::Bitmap* recycledBitmap = nullptr;
size_t recycledBytes = 0;
@ -168,17 +179,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
if (javaBitmap) {
allocator = &recycleAlloc;
// We are required to match the color type of the recycled bitmap.
colorType = recycledBitmap->info().colorType();
decodeColorType = recycledBitmap->info().colorType();
} else {
allocator = &heapAlloc;
}
// Decode the region.
SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
SkBitmapRegionDecoder* brd =
reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
SkBitmap bitmap;
if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize, colorType, requireUnpremul)) {
if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize,
decodeColorType, requireUnpremul, decodeColorSpace)) {
return nullObjectReturn("Failed to decode region.");
}
@ -186,11 +196,23 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint in
if (NULL != options) {
env->SetIntField(options, gOptions_widthFieldID, bitmap.width());
env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
env->SetObjectField(options, gOptions_mimeFieldID,
encodedFormatToString(env, (SkEncodedImageFormat)brd->getEncodedFormat()));
if (env->ExceptionCheck()) {
return nullObjectReturn("OOM in encodedFormatToString()");
}
jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
if (isHardware) {
configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
}
jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
gBitmapConfig_nativeToConfigMethodID, configID);
env->SetObjectField(options, gOptions_outConfigFieldID, config);
env->SetObjectField(options, gOptions_outColorSpaceFieldID,
GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
}
// If we may have reused a bitmap, we need to indicate that the pixels have changed.

View File

@ -6,6 +6,7 @@
#include "jni.h"
#include "JNIHelp.h"
#include "GraphicsJNI.h"
#include "core_jni_helpers.h"
#include "SkCanvas.h"
#include "SkMath.h"
@ -17,6 +18,8 @@
#include <Caches.h>
#include <TextureCache.h>
using namespace android;
void doThrowNPE(JNIEnv* env) {
jniThrowNullPointerException(env, NULL);
}
@ -178,6 +181,32 @@ static jclass gVMRuntime_class;
static jmethodID gVMRuntime_newNonMovableArray;
static jmethodID gVMRuntime_addressOf;
static jfieldID gTransferParams_aFieldID;
static jfieldID gTransferParams_bFieldID;
static jfieldID gTransferParams_cFieldID;
static jfieldID gTransferParams_dFieldID;
static jfieldID gTransferParams_eFieldID;
static jfieldID gTransferParams_fFieldID;
static jfieldID gTransferParams_gFieldID;
static jclass gColorSpace_class;
static jfieldID gColorSpace_IlluminantD50FieldID;
static jmethodID gColorSpace_adaptMethodID;
static jmethodID gColorSpace_getMethodID;
static jmethodID gColorSpace_matchMethodID;
static jclass gColorSpaceRGB_class;
static jmethodID gColorSpaceRGB_getTransferParametersMethodID;
static jmethodID gColorSpaceRGB_getTransformMethodID;
static jmethodID gColorSpaceRGB_constructorMethodID;
static jclass gColorSpace_Named_class;
static jfieldID gColorSpace_Named_sRGBFieldID;
static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
static jclass gTransferParameters_class;
static jmethodID gTransferParameters_constructorMethodID;
///////////////////////////////////////////////////////////////////////////////
void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
@ -328,7 +357,7 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) {
}
void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
android::bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
}
SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject jbitmap) {
@ -464,6 +493,125 @@ bool GraphicsJNI::isColorSpaceSRGB(SkColorSpace* colorSpace) {
return colorSpace == nullptr || colorSpace->isSRGB();
}
SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
SkColorSpaceTransferFn p;
p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
return p;
}
SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
xyzMatrix.setFloat(0, 0, array[0]);
xyzMatrix.setFloat(1, 0, array[1]);
xyzMatrix.setFloat(2, 0, array[2]);
xyzMatrix.setFloat(0, 1, array[3]);
xyzMatrix.setFloat(1, 1, array[4]);
xyzMatrix.setFloat(2, 1, array[5]);
xyzMatrix.setFloat(0, 2, array[6]);
xyzMatrix.setFloat(1, 2, array[7]);
xyzMatrix.setFloat(2, 2, array[8]);
env->ReleaseFloatArrayElements(xyzD50, array, 0);
return xyzMatrix;
}
sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorSpace) {
if (colorSpace == nullptr) return nullptr;
if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
doThrowIAE(env, "The color space must be an RGB color space");
}
jobject transferParams = env->CallObjectMethod(colorSpace,
gColorSpaceRGB_getTransferParametersMethodID);
if (transferParams == nullptr) {
doThrowIAE(env, "The color space must use an ICC parametric transfer function");
}
jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
gColorSpace_IlluminantD50FieldID);
jobject colorSpaceD50 = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_adaptMethodID, colorSpace, illuminantD50);
jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50,
gColorSpaceRGB_getTransformMethodID);
SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams);
return SkColorSpace::MakeRGB(transferFunction, xyzMatrix);
}
jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
SkColorType decodeColorType) {
jobject colorSpace = nullptr;
// No need to match, we know what the output color space will be
if (decodeColorType == kRGBA_F16_SkColorType) {
jobject linearExtendedSRGB = env->GetStaticObjectField(
gColorSpace_Named_class, gColorSpace_Named_LinearExtendedSRGBFieldID);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_getMethodID, linearExtendedSRGB);
} else {
// Same here, no need to match
if (decodeColorSpace->isSRGB()) {
jobject sRGB = env->GetStaticObjectField(
gColorSpace_Named_class, gColorSpace_Named_sRGBFieldID);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_getMethodID, sRGB);
} else if (decodeColorSpace.get() != nullptr) {
// Try to match against known RGB color spaces using the CIE XYZ D50
// conversion matrix and numerical transfer function parameters
SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
SkColorSpaceTransferFn transferParams;
// We can only handle numerical transfer functions at the moment
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
jobject params = env->NewObject(gTransferParameters_class,
gTransferParameters_constructorMethodID,
transferParams.fA, transferParams.fB, transferParams.fC,
transferParams.fD, transferParams.fE, transferParams.fF,
transferParams.fG);
jfloatArray xyzArray = env->NewFloatArray(9);
jfloat xyz[9] = {
xyzMatrix.getFloat(0, 0),
xyzMatrix.getFloat(1, 0),
xyzMatrix.getFloat(2, 0),
xyzMatrix.getFloat(0, 1),
xyzMatrix.getFloat(1, 1),
xyzMatrix.getFloat(2, 1),
xyzMatrix.getFloat(0, 2),
xyzMatrix.getFloat(1, 2),
xyzMatrix.getFloat(2, 2)
};
env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
gColorSpace_matchMethodID, xyzArray, params);
if (colorSpace == nullptr) {
// We couldn't find an exact match, let's create a new color space
// instance with the 3x3 conversion matrix and transfer function
colorSpace = env->NewObject(gColorSpaceRGB_class,
gColorSpaceRGB_constructorMethodID,
env->NewStringUTF("Unknown"), xyzArray, params);
}
env->DeleteLocalRef(xyzArray);
}
}
return colorSpace;
}
///////////////////////////////////////////////////////////////////////////////
bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
mStorage = android::Bitmap::allocateHeapBitmap(bitmap, ctable);
@ -577,74 +725,97 @@ bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable)
////////////////////////////////////////////////////////////////////////////////
static jclass make_globalref(JNIEnv* env, const char classname[])
{
jclass c = env->FindClass(classname);
SkASSERT(c);
return (jclass) env->NewGlobalRef(c);
}
static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
const char fieldname[], const char type[])
{
jfieldID id = env->GetFieldID(clazz, fieldname, type);
SkASSERT(id);
return id;
}
int register_android_graphics_Graphics(JNIEnv* env)
{
jmethodID m;
jclass c;
gRect_class = make_globalref(env, "android/graphics/Rect");
gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
gRect_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Rect"));
gRect_leftFieldID = GetFieldIDOrDie(env, gRect_class, "left", "I");
gRect_topFieldID = GetFieldIDOrDie(env, gRect_class, "top", "I");
gRect_rightFieldID = GetFieldIDOrDie(env, gRect_class, "right", "I");
gRect_bottomFieldID = GetFieldIDOrDie(env, gRect_class, "bottom", "I");
gRectF_class = make_globalref(env, "android/graphics/RectF");
gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
gRectF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/RectF"));
gRectF_leftFieldID = GetFieldIDOrDie(env, gRectF_class, "left", "F");
gRectF_topFieldID = GetFieldIDOrDie(env, gRectF_class, "top", "F");
gRectF_rightFieldID = GetFieldIDOrDie(env, gRectF_class, "right", "F");
gRectF_bottomFieldID = GetFieldIDOrDie(env, gRectF_class, "bottom", "F");
gPoint_class = make_globalref(env, "android/graphics/Point");
gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
gPoint_xFieldID = GetFieldIDOrDie(env, gPoint_class, "x", "I");
gPoint_yFieldID = GetFieldIDOrDie(env, gPoint_class, "y", "I");
gPointF_class = make_globalref(env, "android/graphics/PointF");
gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
gPointF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/PointF"));
gPointF_xFieldID = GetFieldIDOrDie(env, gPointF_class, "x", "F");
gPointF_yFieldID = GetFieldIDOrDie(env, gPointF_class, "y", "F");
gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V");
gBitmapRegionDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/BitmapRegionDecoder"));
gBitmapRegionDecoder_constructorMethodID = GetMethodIDOrDie(env, gBitmapRegionDecoder_class, "<init>", "(J)V");
gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
"nativeInt", "I");
gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config"));
gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I");
gCanvas_class = make_globalref(env, "android/graphics/Canvas");
gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvasWrapper", "J");
gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
gPicture_class = make_globalref(env, "android/graphics/Picture");
gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "J");
gPicture_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Picture"));
gPicture_nativeInstanceID = GetFieldIDOrDie(env, gPicture_class, "mNativePicture", "J");
gRegion_class = make_globalref(env, "android/graphics/Region");
gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "J");
gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
"(JI)V");
gRegion_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Region"));
gRegion_nativeInstanceID = GetFieldIDOrDie(env, gRegion_class, "mNativeRegion", "J");
gRegion_constructorMethodID = GetMethodIDOrDie(env, gRegion_class, "<init>", "(JI)V");
c = env->FindClass("java/lang/Byte");
gByte_class = (jclass) env->NewGlobalRef(
env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;")));
gVMRuntime_class = make_globalref(env, "dalvik/system/VMRuntime");
gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime"));
m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;");
gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m));
gVMRuntime_newNonMovableArray = env->GetMethodID(gVMRuntime_class, "newNonMovableArray",
gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray",
"(Ljava/lang/Class;I)Ljava/lang/Object;");
gVMRuntime_addressOf = env->GetMethodID(gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
jclass transfer_params_class = FindClassOrDie(env, "android/graphics/ColorSpace$Rgb$TransferParameters");
gTransferParams_aFieldID = GetFieldIDOrDie(env, transfer_params_class, "a", "D");
gTransferParams_bFieldID = GetFieldIDOrDie(env, transfer_params_class, "b", "D");
gTransferParams_cFieldID = GetFieldIDOrDie(env, transfer_params_class, "c", "D");
gTransferParams_dFieldID = GetFieldIDOrDie(env, transfer_params_class, "d", "D");
gTransferParams_eFieldID = GetFieldIDOrDie(env, transfer_params_class, "e", "D");
gTransferParams_fFieldID = GetFieldIDOrDie(env, transfer_params_class, "f", "D");
gTransferParams_gFieldID = GetFieldIDOrDie(env, transfer_params_class, "g", "D");
gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
gColorSpace_IlluminantD50FieldID = GetStaticFieldIDOrDie(env,
gColorSpace_class, "ILLUMINANT_D50", "[F");
gColorSpace_adaptMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "adapt",
"(Landroid/graphics/ColorSpace;[F)Landroid/graphics/ColorSpace;");
gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
"get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
"([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;");
gColorSpaceRGB_class = MakeGlobalRefOrDie(env,
FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
"<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
gColorSpaceRGB_getTransferParametersMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
"getTransferParameters", "()Landroid/graphics/ColorSpace$Rgb$TransferParameters;");
gColorSpaceRGB_getTransformMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
"getTransform", "()[F");
gColorSpace_Named_class = MakeGlobalRefOrDie(env,
FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
"android/graphics/ColorSpace$Rgb$TransferParameters"));
gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
"<init>", "(DDDDDDD)V");
return 0;
}

View File

@ -10,6 +10,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkColorSpace.h"
#include "SkMatrix44.h"
#include <jni.h>
#include <hwui/Canvas.h>
#include <hwui/Bitmap.h>
@ -112,6 +113,13 @@ public:
static sk_sp<SkColorSpace> linearColorSpace();
static sk_sp<SkColorSpace> colorSpaceForType(SkColorType type);
static bool isColorSpaceSRGB(SkColorSpace* colorSpace);
static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace);
static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
SkColorType decodeColorType);
};
class HeapAllocator : public SkBRDAllocator {

View File

@ -43,7 +43,6 @@ public class BitmapFactory {
* the same result from the decoder as if null were passed.
*/
public Options() {
inDither = false;
inScaled = true;
inPremultiplied = true;
}
@ -114,8 +113,8 @@ public class BitmapFactory {
/**
* If set to true, the decoder will return null (no bitmap), but
* the out... fields will still be set, allowing the caller to query
* the bitmap without having to allocate the memory for its pixels.
* the <code>out...</code> fields will still be set, allowing the caller to
* query the bitmap without having to allocate the memory for its pixels.
*/
public boolean inJustDecodeBounds;
@ -143,6 +142,35 @@ public class BitmapFactory {
*/
public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;
/**
* <p>If this is non-null, the decoder will try to decode into this
* color space. If it is null, or the request cannot be met,
* the decoder will pick either the color space embedded in the image
* or the color space best suited for the requested image configuration
* (for instance {@link ColorSpace.Named#SRGB sRGB} for
* the {@link Bitmap.Config#ARGB_8888} configuration).</p>
*
* <p>{@link Bitmap.Config#RGBA_F16} always uses the
* {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
* Bitmaps in other configurations without an embedded color space are
* assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
*
* <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
* currently supported. An <code>IllegalArgumentException</code> will
* be thrown by the decode methods when setting a non-RGB color space
* such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
*
* <p class="note">The specified color space's transfer function must be
* an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
* <code>IllegalArgumentException</code> will be thrown by the decode methods
* if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
* specified color space returns null.</p>
*
* <p>After decode, the bitmap's color space is stored in
* {@link #outColorSpace}.</p>
*/
public ColorSpace inPreferredColorSpace = null;
/**
* If true (which is the default), the resulting bitmap will have its
* color channels pre-multipled by the alpha channel.
@ -403,9 +431,22 @@ public class BitmapFactory {
}
static void validate(Options opts) {
if (opts != null && opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
if (opts == null) return;
if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
throw new IllegalArgumentException("Bitmaps with Config.HARWARE are always immutable");
}
if (opts.inPreferredColorSpace != null) {
if (!(opts.inPreferredColorSpace instanceof ColorSpace.Rgb)) {
throw new IllegalArgumentException("The destination color space must use the " +
"RGB color model");
}
if (((ColorSpace.Rgb) opts.inPreferredColorSpace).getTransferParameters() == null) {
throw new IllegalArgumentException("The destination color space must use an " +
"ICC parametric transfer function");
}
}
}
}
@ -421,7 +462,9 @@ public class BitmapFactory {
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeFile(String pathName, Options opts) {
validate(opts);
@ -463,7 +506,9 @@ public class BitmapFactory {
* resources, which we pass to be able to scale the bitmap accordingly.
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeResourceStream(Resources res, TypedValue value,
InputStream is, Rect pad, Options opts) {
@ -501,7 +546,9 @@ public class BitmapFactory {
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeResource(Resources res, int id, Options opts) {
validate(opts);
@ -559,7 +606,9 @@ public class BitmapFactory {
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
if ((offset | length) < 0 || data.length < offset + length) {
@ -641,7 +690,9 @@ public class BitmapFactory {
* size be returned (in opts.outWidth and opts.outHeight)
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*
* <p class="note">Prior to {@link android.os.Build.VERSION_CODES#KITKAT},
* if {@link InputStream#markSupported is.markSupported()} returns true,
@ -720,7 +771,9 @@ public class BitmapFactory {
* @return the decoded bitmap, or null
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
validate(opts);

View File

@ -180,7 +180,9 @@ public final class BitmapRegionDecoder {
* decoded.
* @throws IllegalArgumentException if {@link BitmapFactory.Options#inPreferredConfig}
* is {@link android.graphics.Bitmap.Config#HARDWARE}
* and {@link BitmapFactory.Options#inMutable} is set.
* and {@link BitmapFactory.Options#inMutable} is set, if the specified color space
* is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
* function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
*/
public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
BitmapFactory.Options.validate(options);