Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efb4b064 authored by Romain Guy's avatar Romain Guy
Browse files

Add ColorSpace information on Bitmap

This is the first step toward interpreting color spaces at render time.

Bug: 32984164
Test: BitmapColorSpaceTest in CtsGraphicsTestCases

Change-Id: I0164a18f1ed74a745874fe5229168042afe27a04
parent 4f357c08
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -12201,6 +12201,7 @@ package android.graphics {
    method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
    method public final int getAllocationByteCount();
    method public final int getByteCount();
    method public final android.graphics.ColorSpace getColorSpace();
    method public final android.graphics.Bitmap.Config getConfig();
    method public int getDensity();
    method public int getGenerationId();
@@ -12583,6 +12584,7 @@ package android.graphics {
    method public java.lang.String getName();
    method public boolean isSrgb();
    method public abstract boolean isWideGamut();
    method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    method public float[] toXyz(float, float, float);
    method public abstract float[] toXyz(float[]);
    field public static final float[] ILLUMINANT_A;
@@ -12667,6 +12669,10 @@ package android.graphics {
  public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
    ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
    ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], double);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
    method public float[] fromLinear(float, float, float);
    method public float[] fromLinear(float[]);
    method public float[] fromXyz(float[]);
@@ -12678,6 +12684,7 @@ package android.graphics {
    method public java.util.function.DoubleUnaryOperator getOetf();
    method public float[] getPrimaries(float[]);
    method public float[] getPrimaries();
    method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
    method public float[] getTransform(float[]);
    method public float[] getTransform();
    method public float[] getWhitePoint(float[]);
@@ -12688,6 +12695,18 @@ package android.graphics {
    method public float[] toXyz(float[]);
  }
  public static class ColorSpace.Rgb.TransferParameters {
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
    field public final double a;
    field public final double b;
    field public final double c;
    field public final double d;
    field public final double e;
    field public final double f;
    field public final double g;
  }
  public class ComposePathEffect extends android.graphics.PathEffect {
    ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
  }
+19 −0
Original line number Diff line number Diff line
@@ -12836,6 +12836,7 @@ package android.graphics {
    method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
    method public final int getAllocationByteCount();
    method public final int getByteCount();
    method public final android.graphics.ColorSpace getColorSpace();
    method public final android.graphics.Bitmap.Config getConfig();
    method public int getDensity();
    method public int getGenerationId();
@@ -13218,6 +13219,7 @@ package android.graphics {
    method public java.lang.String getName();
    method public boolean isSrgb();
    method public abstract boolean isWideGamut();
    method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    method public float[] toXyz(float, float, float);
    method public abstract float[] toXyz(float[]);
    field public static final float[] ILLUMINANT_A;
@@ -13302,6 +13304,10 @@ package android.graphics {
  public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
    ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
    ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], double);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
    method public float[] fromLinear(float, float, float);
    method public float[] fromLinear(float[]);
    method public float[] fromXyz(float[]);
@@ -13313,6 +13319,7 @@ package android.graphics {
    method public java.util.function.DoubleUnaryOperator getOetf();
    method public float[] getPrimaries(float[]);
    method public float[] getPrimaries();
    method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
    method public float[] getTransform(float[]);
    method public float[] getTransform();
    method public float[] getWhitePoint(float[]);
@@ -13323,6 +13330,18 @@ package android.graphics {
    method public float[] toXyz(float[]);
  }
  public static class ColorSpace.Rgb.TransferParameters {
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
    field public final double a;
    field public final double b;
    field public final double c;
    field public final double d;
    field public final double e;
    field public final double f;
    field public final double g;
  }
  public class ComposePathEffect extends android.graphics.PathEffect {
    ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
  }
+19 −0
Original line number Diff line number Diff line
@@ -12238,6 +12238,7 @@ package android.graphics {
    method public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]);
    method public final int getAllocationByteCount();
    method public final int getByteCount();
    method public final android.graphics.ColorSpace getColorSpace();
    method public final android.graphics.Bitmap.Config getConfig();
    method public int getDensity();
    method public int getGenerationId();
@@ -12620,6 +12621,7 @@ package android.graphics {
    method public java.lang.String getName();
    method public boolean isSrgb();
    method public abstract boolean isWideGamut();
    method public static android.graphics.ColorSpace match(float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    method public float[] toXyz(float, float, float);
    method public abstract float[] toXyz(float[]);
    field public static final float[] ILLUMINANT_A;
@@ -12704,6 +12706,10 @@ package android.graphics {
  public static class ColorSpace.Rgb extends android.graphics.ColorSpace {
    ctor public ColorSpace.Rgb(java.lang.String, float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], java.util.function.DoubleUnaryOperator, java.util.function.DoubleUnaryOperator, float, float);
    ctor public ColorSpace.Rgb(java.lang.String, float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], android.graphics.ColorSpace.Rgb.TransferParameters);
    ctor public ColorSpace.Rgb(java.lang.String, float[], double);
    ctor public ColorSpace.Rgb(java.lang.String, float[], float[], double);
    method public float[] fromLinear(float, float, float);
    method public float[] fromLinear(float[]);
    method public float[] fromXyz(float[]);
@@ -12715,6 +12721,7 @@ package android.graphics {
    method public java.util.function.DoubleUnaryOperator getOetf();
    method public float[] getPrimaries(float[]);
    method public float[] getPrimaries();
    method public android.graphics.ColorSpace.Rgb.TransferParameters getTransferParameters();
    method public float[] getTransform(float[]);
    method public float[] getTransform();
    method public float[] getWhitePoint(float[]);
@@ -12725,6 +12732,18 @@ package android.graphics {
    method public float[] toXyz(float[]);
  }
  public static class ColorSpace.Rgb.TransferParameters {
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double);
    ctor public ColorSpace.Rgb.TransferParameters(double, double, double, double, double, double, double);
    field public final double a;
    field public final double b;
    field public final double c;
    field public final double d;
    field public final double e;
    field public final double f;
    field public final double g;
  }
  public class ComposePathEffect extends android.graphics.PathEffect {
    ctor public ComposePathEffect(android.graphics.PathEffect, android.graphics.PathEffect);
  }
+59 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkHalf.h"
#include "SkMatrix44.h"
#include "SkPM4f.h"
#include "SkPM4fPriv.h"
#include "GraphicsJNI.h"
@@ -1168,6 +1169,61 @@ static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,

///////////////////////////////////////////////////////////////////////////////

static jboolean Bitmap_isSRGB(JNIEnv* env, jobject, jlong bitmapHandle) {
    LocalScopedBitmap bitmapHolder(bitmapHandle);
    if (!bitmapHolder.valid()) return JNI_TRUE;

    SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
    return colorSpace == nullptr ||
           colorSpace == SkColorSpace::MakeSRGB().get() ||
           colorSpace == SkColorSpace::MakeRGB(
                  SkColorSpace::kSRGB_RenderTargetGamma,
                  SkColorSpace::kSRGB_Gamut,
                  SkColorSpace::kNonLinearBlending_ColorSpaceFlag).get();
}

static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
        jfloatArray xyzArray, jfloatArray paramsArray) {

    LocalScopedBitmap bitmapHolder(bitmapHandle);
    if (!bitmapHolder.valid()) return JNI_FALSE;

    SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
    if (colorSpace == nullptr) return JNI_FALSE;

    SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
    if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;

    jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
    xyz[0] = xyzMatrix.getFloat(0, 0);
    xyz[1] = xyzMatrix.getFloat(1, 0);
    xyz[2] = xyzMatrix.getFloat(2, 0);
    xyz[3] = xyzMatrix.getFloat(0, 1);
    xyz[4] = xyzMatrix.getFloat(1, 1);
    xyz[5] = xyzMatrix.getFloat(2, 1);
    xyz[6] = xyzMatrix.getFloat(0, 2);
    xyz[7] = xyzMatrix.getFloat(1, 2);
    xyz[8] = xyzMatrix.getFloat(2, 2);
    env->ReleaseFloatArrayElements(xyzArray, xyz, 0);

    SkColorSpaceTransferFn transferParams;
    if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;

    jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
    params[0] = transferParams.fA;
    params[1] = transferParams.fB;
    params[2] = transferParams.fC;
    params[3] = transferParams.fD;
    params[4] = transferParams.fE;
    params[5] = transferParams.fF;
    params[6] = transferParams.fG;
    env->ReleaseFloatArrayElements(paramsArray, params, 0);

    return JNI_TRUE;
}

///////////////////////////////////////////////////////////////////////////////

static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
        jint x, jint y) {
    SkBitmap bitmap;
@@ -1459,7 +1515,9 @@ static const JNINativeMethod gBitmapMethods[] = {
    {   "nativeCreateHardwareBitmap", "(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;",
        (void*) Bitmap_createHardwareBitmap },
    {   "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
        (void*) Bitmap_createGraphicBufferHandle }
        (void*) Bitmap_createGraphicBufferHandle },
    {   "nativeGetColorSpace",      "(J[F[F)Z", (void*)Bitmap_getColorSpace },
    {   "nativeIsSRGB",             "(J)Z", (void*)Bitmap_isSRGB },
};

int register_android_graphics_Bitmap(JNIEnv* env)
+46 −1
Original line number Diff line number Diff line
@@ -19,12 +19,12 @@ package android.graphics;
import android.annotation.CheckResult;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Trace;
import android.util.DisplayMetrics;
import android.util.Log;

import libcore.util.NativeAllocationRegistry;

import java.io.OutputStream;
@@ -73,6 +73,8 @@ public final class Bitmap implements Parcelable {
    private int mHeight;
    private boolean mRecycled;

    private ColorSpace mColorSpace;

    /** @hide */
    public int mDensity = getDefaultDensity();

@@ -1434,6 +1436,47 @@ public final class Bitmap implements Parcelable {
        nativeSetHasMipMap(mNativePtr, hasMipMap);
    }

    /**
     * Returns the color space associated with this bitmap. If the color
     * space is unknown, this method returns null.
     */
    @Nullable
    public final ColorSpace getColorSpace() {
        // A reconfigure can change the configuration and rgba16f is
        // always linear scRGB at this time
        if (getConfig() == Config.RGBA_F16) {
            // Reset the color space for potential future reconfigurations
            mColorSpace = null;
            return ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
        }

        // Cache the color space retrieval since it can be fairly expensive
        if (mColorSpace == null) {
            if (nativeIsSRGB(mNativePtr)) {
                mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
            } else {
                float[] xyz = new float[9];
                float[] params = new float[7];

                boolean hasColorSpace = nativeGetColorSpace(mNativePtr, xyz, params);
                if (hasColorSpace) {
                    ColorSpace.Rgb.TransferParameters parameters =
                            new ColorSpace.Rgb.TransferParameters(
                                    params[0], params[1], params[2],
                                    params[3], params[4], params[5], params[6]);
                    ColorSpace cs = ColorSpace.match(xyz, parameters);
                    if (cs != null) {
                        mColorSpace = cs;
                    } else {
                        mColorSpace = new ColorSpace.Rgb("Unknown", xyz, parameters);
                    }
                }
            }
        }

        return mColorSpace;
    }

    /**
     * Fills the bitmap's pixels with the specified {@link Color}.
     *
@@ -1816,4 +1859,6 @@ public final class Bitmap implements Parcelable {
    private static native Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap);
    private static native Bitmap nativeCreateHardwareBitmap(GraphicBuffer buffer);
    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);
}
Loading