diff --git a/api/current.txt b/api/current.txt index fcd5c8c7da15f..aa4236c60a6c1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -12429,7 +12429,9 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); diff --git a/api/system-current.txt b/api/system-current.txt index 02f454825504a..88191817b5a91 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -13192,7 +13192,9 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); diff --git a/api/test-current.txt b/api/test-current.txt index fb460310439ab..700640192ea2c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12479,7 +12479,9 @@ package android.graphics { method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean); + method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int, int, android.graphics.Bitmap.Config, boolean, android.graphics.ColorSpace); method public static android.graphics.Bitmap createBitmap(int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(android.util.DisplayMetrics, int[], int, int, int, int, android.graphics.Bitmap.Config); method public static android.graphics.Bitmap createBitmap(int[], int, int, android.graphics.Bitmap.Config); diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index de5e505af3daa..3a03af60efcec 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -44,6 +44,14 @@ 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 { @@ -685,6 +693,22 @@ static ToColorProc ChooseToColorProc(const SkBitmap& src) { return NULL; } +static void ToF16_SA8(void* dst, const void* src, int width) { + SkASSERT(width > 0); + uint64_t* d = (uint64_t*)dst; + const uint8_t* s = (const uint8_t*)src; + + for (int i = 0; i < width; i++) { + uint8_t c = *s++; + SkPM4f a; + a.fVec[SkPM4f::R] = 0.0f; + a.fVec[SkPM4f::G] = 0.0f; + a.fVec[SkPM4f::B] = 0.0f; + a.fVec[SkPM4f::A] = c / 255.0f; + *d++ = a.toF16(); + } +} + /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -696,7 +720,8 @@ static int getPremulBitmapCreateFlags(bool isMutable) { static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, jint offset, jint stride, jint width, jint height, - jint configHandle, jboolean isMutable) { + jint configHandle, jboolean isMutable, + jfloatArray xyzD50, jobject transferParameters) { SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); if (NULL != jColors) { size_t n = env->GetArrayLength(jColors); @@ -712,8 +737,37 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, } SkBitmap bitmap; - bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, - GraphicsJNI::colorSpaceForType(colorType))); + sk_sp colorSpace; + + 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); + + colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix); + } + + bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace)); sk_sp nativeBitmap = Bitmap::allocateHeapBitmap(&bitmap, NULL); if (!nativeBitmap) { @@ -739,6 +793,9 @@ static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src, SkPixmap srcPixmap = srcUnlocker.pixmap(); SkImageInfo dstInfo = src.info().makeColorType(dstCT); + if (dstCT == kRGBA_F16_SkColorType) { + dstInfo = dstInfo.makeColorSpace(SkColorSpace::MakeSRGBLinear()); + } if (!dst->setInfo(dstInfo)) { return false; } @@ -763,6 +820,14 @@ static bool bitmapCopyTo(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src, } return true; } + case kRGBA_F16_SkColorType: { + for (int y = 0; y < src.height(); y++) { + const uint8_t* srcRow = srcPixmap.addr8(0, y); + void* dstRow = dst->getAddr(0, y); + ToF16_SA8(dstRow, srcRow, src.width()); + } + return true; + } default: return false; } @@ -1562,6 +1627,13 @@ static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitm return createJavaGraphicBuffer(env, buffer); } +static void Bitmap_copyColorSpace(JNIEnv* env, jobject, jlong srcBitmapPtr, jlong dstBitmapPtr) { + LocalScopedBitmap srcBitmapHandle(srcBitmapPtr); + LocalScopedBitmap dstBitmapHandle(dstBitmapPtr); + + dstBitmapHandle->bitmap().setColorSpace(srcBitmapHandle->bitmap().info().refColorSpace()); +} + /////////////////////////////////////////////////////////////////////////////// static jclass make_globalref(JNIEnv* env, const char classname[]) { @@ -1579,7 +1651,7 @@ static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz, } static const JNINativeMethod gBitmapMethods[] = { - { "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;", + { "nativeCreate", "([IIIIIIZ[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/Bitmap;", (void*)Bitmap_creator }, { "nativeCopy", "(JIZ)Landroid/graphics/Bitmap;", (void*)Bitmap_copy }, @@ -1628,10 +1700,21 @@ static const JNINativeMethod gBitmapMethods[] = { (void*) Bitmap_createGraphicBufferHandle }, { "nativeGetColorSpace", "(J[F[F)Z", (void*)Bitmap_getColorSpace }, { "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB }, + { "nativeCopyColorSpace", "(JJ)V", + (void*)Bitmap_copyColorSpace }, }; 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, "", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V"); diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index ed587bbaed241..919068500e6fd 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -20,6 +20,7 @@ import android.annotation.CheckResult; import android.annotation.ColorInt; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.Size; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -78,8 +79,6 @@ public final class Bitmap implements Parcelable { /** @hide */ public int mDensity = getDefaultDensity(); - private static volatile Matrix sScaleMatrix; - private static volatile int sDefaultDensity = -1; /** @@ -606,7 +605,7 @@ public final class Bitmap implements Parcelable { * setting the new bitmap's config to the one specified, and then copying * this bitmap's pixels into the new bitmap. If the conversion is not * supported, or the allocator fails, then this returns NULL. The returned - * bitmap initially has the same density as the original. + * bitmap has the same density and color space as the original. * * @param config The desired config for the resulting bitmap * @param isMutable True if the resulting bitmap should be mutable (i.e. @@ -629,7 +628,8 @@ public final class Bitmap implements Parcelable { /** * Creates a new immutable bitmap backed by ashmem which can efficiently - * be passed between processes. + * be passed between processes. The bitmap is assumed to be in the sRGB + * color space. * * @hide */ @@ -645,7 +645,8 @@ public final class Bitmap implements Parcelable { /** * Creates a new immutable bitmap backed by ashmem which can efficiently - * be passed between processes. + * be passed between processes. The bitmap is assumed to be in the sRGB + * color space. * * @hide */ @@ -666,7 +667,7 @@ public final class Bitmap implements Parcelable { * currently PIXEL_FORMAT_RGBA_8888 is the only supported format * @hide */ - public static Bitmap createHardwareBitmap(GraphicBuffer graphicBuffer) { + public static Bitmap createHardwareBitmap(@NonNull GraphicBuffer graphicBuffer) { return nativeCreateHardwareBitmap(graphicBuffer); } @@ -683,50 +684,34 @@ public final class Bitmap implements Parcelable { * @return The new scaled bitmap or the source bitmap if no scaling is required. * @throws IllegalArgumentException if width is <= 0, or height is <= 0 */ - public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, + public static Bitmap createScaledBitmap(@NonNull Bitmap src, int dstWidth, int dstHeight, boolean filter) { - Matrix m; - synchronized (Bitmap.class) { - // small pool of just 1 matrix - m = sScaleMatrix; - sScaleMatrix = null; - } - - if (m == null) { - m = new Matrix(); - } + Matrix m = new Matrix(); final int width = src.getWidth(); final int height = src.getHeight(); - final float sx = dstWidth / (float)width; - final float sy = dstHeight / (float)height; - m.setScale(sx, sy); - Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter); - - synchronized (Bitmap.class) { - // do we need to check for null? why not just assign everytime? - if (sScaleMatrix == null) { - sScaleMatrix = m; - } + if (width != dstWidth || height != dstHeight) { + final float sx = dstWidth / (float) width; + final float sy = dstHeight / (float) height; + m.setScale(sx, sy); } - - return b; + return Bitmap.createBitmap(src, 0, 0, width, height, m, filter); } /** * Returns an immutable bitmap from the source bitmap. The new bitmap may * be the same object as source, or a copy may have been made. It is - * initialized with the same density as the original bitmap. + * initialized with the same density and color space as the original bitmap. */ - public static Bitmap createBitmap(Bitmap src) { + public static Bitmap createBitmap(@NonNull Bitmap src) { return createBitmap(src, 0, 0, src.getWidth(), src.getHeight()); } /** * Returns an immutable bitmap from the specified subset of the source * bitmap. The new bitmap may be the same object as source, or a copy may - * have been made. It is initialized with the same density as the original - * bitmap. + * have been made. It is initialized with the same density and color space + * as the original bitmap. * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source @@ -738,7 +723,7 @@ public final class Bitmap implements Parcelable { * outside of the dimensions of the source bitmap, or width is <= 0, * or height is <= 0 */ - public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { + public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) { return createBitmap(source, x, y, width, height, null, false); } @@ -746,7 +731,8 @@ public final class Bitmap implements Parcelable { * Returns an immutable bitmap from subset of the source bitmap, * transformed by the optional matrix. The new bitmap may be the * same object as source, or a copy may have been made. It is - * initialized with the same density as the original bitmap. + * initialized with the same density and color space as the original + * bitmap. * * If the source bitmap is immutable and the requested subset is the * same as the source bitmap itself, then the source bitmap is @@ -766,8 +752,8 @@ public final class Bitmap implements Parcelable { * outside of the dimensions of the source bitmap, or width is <= 0, * or height is <= 0 */ - public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, - Matrix m, boolean filter) { + public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height, + @Nullable Matrix m, boolean filter) { checkXYSign(x, y); checkWidthHeight(width, height); @@ -847,6 +833,8 @@ public final class Bitmap implements Parcelable { } } + nativeCopyColorSpace(source.mNativePtr, bitmap.mNativePtr); + // The new bitmap was created from a known bitmap source so assume that // they use the same density bitmap.mDensity = source.mDensity; @@ -866,7 +854,8 @@ public final class Bitmap implements Parcelable { /** * Returns a mutable bitmap with the specified width and height. Its - * initial density is as per {@link #getDensity}. + * initial density is as per {@link #getDensity}. The newly created + * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space. * * @param width The width of the bitmap * @param height The height of the bitmap @@ -874,13 +863,15 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * Config is Config.HARDWARE, because hardware bitmaps are always immutable */ - public static Bitmap createBitmap(int width, int height, Config config) { + public static Bitmap createBitmap(int width, int height, @NonNull Config config) { return createBitmap(width, height, config, true); } /** * Returns a mutable bitmap with the specified width and height. Its * initial density is determined from the given {@link DisplayMetrics}. + * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB} + * color space. * * @param display Display metrics for the display this bitmap will be * drawn on. @@ -890,11 +881,31 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * Config is Config.HARDWARE, because hardware bitmaps are always immutable */ - public static Bitmap createBitmap(DisplayMetrics display, int width, - int height, Config config) { + public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, + int height, @NonNull Config config) { return createBitmap(display, width, height, config, true); } + /** + * Returns a mutable bitmap with the specified width and height. Its + * initial density is as per {@link #getDensity}. The newly created + * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space. + * + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. + * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to + * mark the bitmap as opaque. Doing so will clear the bitmap in black + * instead of transparent. + * + * @throws IllegalArgumentException if the width or height are <= 0, or if + * Config is Config.HARDWARE, because hardware bitmaps are always immutable + */ + public static Bitmap createBitmap(int width, int height, + @NonNull Config config, boolean hasAlpha) { + return createBitmap(null, width, height, config, hasAlpha); + } + /** * Returns a mutable bitmap with the specified width and height. Its * initial density is as per {@link #getDensity}. @@ -905,17 +916,26 @@ public final class Bitmap implements Parcelable { * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to * mark the bitmap as opaque. Doing so will clear the bitmap in black * instead of transparent. + * @param colorSpace The color space of the bitmap. If null, + * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is + * ignored if the config is not {@link Config#ARGB_8888}. * - * @throws IllegalArgumentException if the width or height are <= 0, or if - * Config is Config.HARDWARE, because hardware bitmaps are always immutable + * @throws IllegalArgumentException if the width or height are <= 0, if + * Config is Config.HARDWARE (because hardware bitmaps are always + * immutable), 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 createBitmap(int width, int height, Config config, boolean hasAlpha) { - return createBitmap(null, width, height, config, hasAlpha); + public static Bitmap createBitmap(int width, int height, @NonNull Config config, + boolean hasAlpha, @Nullable ColorSpace colorSpace) { + return createBitmap(null, width, height, config, hasAlpha, colorSpace); } /** * Returns a mutable bitmap with the specified width and height. Its * initial density is determined from the given {@link DisplayMetrics}. + * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB} + * color space. * * @param display Display metrics for the display this bitmap will be * drawn on. @@ -929,15 +949,63 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * Config is Config.HARDWARE, because hardware bitmaps are always immutable */ - public static Bitmap createBitmap(DisplayMetrics display, int width, int height, - Config config, boolean hasAlpha) { + public static Bitmap createBitmap(@Nullable DisplayMetrics display, int width, int height, + @NonNull Config config, boolean hasAlpha) { + return createBitmap(display, width, height, config, hasAlpha, null); + } + + /** + * Returns a mutable bitmap with the specified width and height. Its + * initial density is determined from the given {@link DisplayMetrics}. + * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB} + * color space. + * + * @param display Display metrics for the display this bitmap will be + * drawn on. + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. + * @param hasAlpha If the bitmap is ARGB_8888 or RGBA_16F this flag can be used to + * mark the bitmap as opaque. Doing so will clear the bitmap in black + * instead of transparent. + * @param colorSpace The color space of the bitmap. If null, + * {@link ColorSpace.Named#SRGB sRGB} is assumed. This argument is + * ignored if the config is not {@link Config#ARGB_8888}. + * + * @throws IllegalArgumentException if the width or height are <= 0, if + * Config is Config.HARDWARE (because hardware bitmaps are always + * immutable), 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 createBitmap(@Nullable DisplayMetrics display, int width, int height, + @NonNull Config config, boolean hasAlpha, @Nullable ColorSpace colorSpace) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } if (config == Config.HARDWARE) { throw new IllegalArgumentException("can't create mutable bitmap with Config.HARDWARE"); } - Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true); + + Bitmap bm; + if (colorSpace == null || config != Config.ARGB_8888) { + bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, null, null); + } else { + if (!(colorSpace instanceof ColorSpace.Rgb)) { + throw new IllegalArgumentException("colorSpace must be an RGB color space"); + } + ColorSpace.Rgb rgb = (ColorSpace.Rgb) colorSpace; + ColorSpace.Rgb.TransferParameters parameters = rgb.getTransferParameters(); + if (parameters == null) { + throw new IllegalArgumentException("colorSpace must use an ICC " + + "parametric transfer function"); + } + + ColorSpace.Rgb d50 = (ColorSpace.Rgb) ColorSpace.adapt(rgb, ColorSpace.ILLUMINANT_D50); + bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true, + d50.getTransform(), parameters); + } + if (display != null) { bm.mDensity = display.densityDpi; } @@ -954,9 +1022,10 @@ public final class Bitmap implements Parcelable { /** * Returns a immutable bitmap with the specified width and height, with each * pixel value set to the corresponding value in the colors array. Its - * initial density is as per {@link #getDensity}. + * initial density is as per {@link #getDensity}. The newly created + * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space. * - * @param colors Array of {@link Color} used to initialize the pixels. + * @param colors Array of sRGB {@link Color colors} used to initialize the pixels. * @param offset Number of values to skip before the first color in the * array of colors. * @param stride Number of colors in the array between rows (must be >= @@ -969,8 +1038,8 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * the color array's length is less than the number of pixels. */ - public static Bitmap createBitmap(int colors[], int offset, int stride, - int width, int height, Config config) { + public static Bitmap createBitmap(@NonNull @ColorInt int[] colors, int offset, int stride, + int width, int height, @NonNull Config config) { return createBitmap(null, colors, offset, stride, width, height, config); } @@ -978,10 +1047,12 @@ public final class Bitmap implements Parcelable { * Returns a immutable bitmap with the specified width and height, with each * pixel value set to the corresponding value in the colors array. Its * initial density is determined from the given {@link DisplayMetrics}. + * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB} + * color space. * * @param display Display metrics for the display this bitmap will be * drawn on. - * @param colors Array of {@link Color} used to initialize the pixels. + * @param colors Array of sRGB {@link Color colors} used to initialize the pixels. * @param offset Number of values to skip before the first color in the * array of colors. * @param stride Number of colors in the array between rows (must be >= @@ -994,8 +1065,9 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * the color array's length is less than the number of pixels. */ - public static Bitmap createBitmap(DisplayMetrics display, int colors[], - int offset, int stride, int width, int height, Config config) { + public static Bitmap createBitmap(@NonNull DisplayMetrics display, + @NonNull @ColorInt int[] colors, int offset, int stride, + int width, int height, @NonNull Config config) { checkWidthHeight(width, height); if (Math.abs(stride) < width) { @@ -1011,7 +1083,7 @@ public final class Bitmap implements Parcelable { throw new IllegalArgumentException("width and height must be > 0"); } Bitmap bm = nativeCreate(colors, offset, stride, width, height, - config.nativeInt, false); + config.nativeInt, false, null, null); if (display != null) { bm.mDensity = display.densityDpi; } @@ -1021,9 +1093,10 @@ public final class Bitmap implements Parcelable { /** * Returns a immutable bitmap with the specified width and height, with each * pixel value set to the corresponding value in the colors array. Its - * initial density is as per {@link #getDensity}. + * initial density is as per {@link #getDensity}. The newly created + * bitmap is in the {@link ColorSpace.Named#SRGB sRGB} color space. * - * @param colors Array of {@link Color} used to initialize the pixels. + * @param colors Array of sRGB {@link Color colors} used to initialize the pixels. * This array must be at least as large as width * height. * @param width The width of the bitmap * @param height The height of the bitmap @@ -1033,7 +1106,8 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * the color array's length is less than the number of pixels. */ - public static Bitmap createBitmap(int colors[], int width, int height, Config config) { + public static Bitmap createBitmap(@NonNull @ColorInt int[] colors, + int width, int height, Config config) { return createBitmap(null, colors, 0, width, width, height, config); } @@ -1041,10 +1115,12 @@ public final class Bitmap implements Parcelable { * Returns a immutable bitmap with the specified width and height, with each * pixel value set to the corresponding value in the colors array. Its * initial density is determined from the given {@link DisplayMetrics}. + * The newly created bitmap is in the {@link ColorSpace.Named#SRGB sRGB} + * color space. * * @param display Display metrics for the display this bitmap will be * drawn on. - * @param colors Array of {@link Color} used to initialize the pixels. + * @param colors Array of sRGB {@link Color colors} used to initialize the pixels. * This array must be at least as large as width * height. * @param width The width of the bitmap * @param height The height of the bitmap @@ -1054,8 +1130,8 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0, or if * the color array's length is less than the number of pixels. */ - public static Bitmap createBitmap(DisplayMetrics display, int colors[], - int width, int height, Config config) { + public static Bitmap createBitmap(@Nullable DisplayMetrics display, + @NonNull @ColorInt int colors[], int width, int height, @NonNull Config config) { return createBitmap(display, colors, 0, width, width, height, config); } @@ -1806,7 +1882,9 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCreate(int[] colors, int offset, int stride, int width, int height, - int nativeConfig, boolean mutable); + int nativeConfig, boolean mutable, + @Nullable @Size(9) float[] xyzD50, + @Nullable ColorSpace.Rgb.TransferParameters p); private static native Bitmap nativeCopy(long nativeSrcBitmap, int nativeConfig, boolean isMutable); private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap); @@ -1865,4 +1943,5 @@ public final class Bitmap implements Parcelable { private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap); private static native boolean nativeGetColorSpace(long nativePtr, float[] xyz, float[] params); private static native boolean nativeIsSRGB(long nativePtr); + private static native void nativeCopyColorSpace(long srcBitmap, long dstBitmap); } diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 13d7e09b6e79b..9f649ead2b52c 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -58,8 +58,10 @@ SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB) } SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) { + sk_sp cs = bitmap.refColorSpace(); mCanvasOwned = std::unique_ptr(new SkCanvas(bitmap)); - mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB()); + mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), + cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); mCanvas = mCanvasWrapper.get(); } @@ -97,9 +99,10 @@ private: }; void SkiaCanvas::setBitmap(const SkBitmap& bitmap) { + sk_sp cs = bitmap.refColorSpace(); std::unique_ptr newCanvas = std::unique_ptr(new SkCanvas(bitmap)); - std::unique_ptr newCanvasWrapper = - SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB()); + std::unique_ptr newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), + cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs)); if (!bitmap.isNull()) { // Copy the canvas matrix & clip state. diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 729c7b8a1ecb7..d7f75fc7fd655 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -322,6 +322,12 @@ sk_sp Bitmap::createFrom(sp graphicBuffer) { return sk_sp(new Bitmap(graphicBuffer.get(), info)); } +void Bitmap::setColorSpace(sk_sp colorSpace) { + // TODO: See todo in reconfigure() below + SkImageInfo* myInfo = const_cast(&this->info()); + *myInfo = info().makeColorSpace(std::move(colorSpace)); +} + void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) { if (kIndex_8_SkColorType != newInfo.colorType()) { ctable = nullptr; diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index 518be032c0eb9..da45f7697f56f 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include #include @@ -82,6 +83,7 @@ public: void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); void reconfigure(const SkImageInfo& info); + void setColorSpace(sk_sp colorSpace); void setAlphaType(SkAlphaType alphaType); void getSkBitmap(SkBitmap* outBitmap);