diff options
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rwxr-xr-x | core/jni/android/graphics/Bitmap.cpp | 65 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapFactory.cpp | 112 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapFactory.h | 6 | ||||
| -rw-r--r-- | core/jni/android/graphics/BitmapRegionDecoder.cpp | 30 | ||||
| -rw-r--r-- | core/jni/android/graphics/Graphics.cpp | 267 | ||||
| -rw-r--r-- | core/jni/android/graphics/GraphicsJNI.h | 8 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BitmapFactory.java | 73 | ||||
| -rw-r--r-- | graphics/java/android/graphics/BitmapRegionDecoder.java | 4 |
11 files changed, 344 insertions, 224 deletions
diff --git a/api/current.txt b/api/current.txt index 4149d03ffeac..e1c57bfb7fc6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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; diff --git a/api/system-current.txt b/api/system-current.txt index 4fa96aef9eec..8fef344fc8fd 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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; diff --git a/api/test-current.txt b/api/test-current.txt index 1fed00758057..e22cc90342f5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -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; diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 3a03af60efce..0e67d304c66d 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -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)); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index a38acd3cb459..e714671027d6 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -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)); } diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h index 76db41dca53f..1ee49fa0af77 100644 --- a/core/jni/android/graphics/BitmapFactory.h +++ b/core/jni/android/graphics/BitmapFactory.h @@ -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); diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index 3247851a0ede..5022b22e8ea7 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -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. diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index e66587a9d8fe..452d0a941c7b 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -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; } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 7d7c88159a55..7fbea2589730 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -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 { diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index ceedc1fdb360..3b272c8ddec7 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -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; @@ -144,6 +143,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); diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java index 04abca1f4bd4..2da27c7dfdbf 100644 --- a/graphics/java/android/graphics/BitmapRegionDecoder.java +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -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); |