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

Commit 4c4259b3 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

Add Bitmap#eraseColor(@ColorLong) + helpers

Bug: 120904891
Test: I162451ebf807f3a8a44679e5c10406468c922500

- Add Bitmap#eraseColor(@ColorLong). This allows erasing in ColorSpaces
  besides SRGB. New API is hidden pending API-council approval. It is
  @TestApi so it can be used by the new tests.
- Rewrite Bitmap#erase(@ColorInt)'s internals. The ColorInt should be
  treated as an SRGB color. The old code (deep in SkPixmap::erase)
  treated the color as being in the SkColorSpace of the SkBitmap.
- Update getNativeColorSpace to return immediately when it throws.
  Existing callers should never throw anyway, since they do their own
  checks (and throws) in Java before reaching this method. But relying
  on this method to properly return simplifies the new callers.

Change-Id: I1b736934ce1b8294c827bb61c2a363207569da4f
parent 5ca575ae
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -494,6 +494,10 @@ package android.database.sqlite {

package android.graphics {

  public final class Bitmap implements android.os.Parcelable {
    method public void eraseColor(long);
  }

  public final class ImageDecoder implements java.lang.AutoCloseable {
    method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
  }
+25 −1
Original line number Diff line number Diff line
@@ -568,11 +568,34 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
    return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
}

static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
        const sk_sp<SkColorSpace>& colorSpace) {
    SkPaint p;
    p.setColor4f(color, colorSpace.get());
    p.setBlendMode(SkBlendMode::kSrc);
    SkCanvas canvas(bitmap);
    canvas.drawPaint(p);
}

static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
    LocalScopedBitmap bitmap(bitmapHandle);
    SkBitmap skBitmap;
    bitmap->getSkBitmap(&skBitmap);
    skBitmap.eraseColor(color);
    bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
}

static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle, jobject jColorSpace,
        jfloat r, jfloat g, jfloat b, jfloat a) {
    sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
    if (GraphicsJNI::hasException(env)) {
        return;
    }

    LocalScopedBitmap bitmap(bitmapHandle);
    SkBitmap skBitmap;
    bitmap->getSkBitmap(&skBitmap);
    SkColor4f color = SkColor4f{r, g, b, a};
    bitmapErase(skBitmap, color, cs);
}

static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -1183,6 +1206,7 @@ static const JNINativeMethod gBitmapMethods[] = {
    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
        (void*)Bitmap_compress },
    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
    {   "nativeErase",              "(JLandroid/graphics/ColorSpace;FFFF)V", (void*)Bitmap_eraseLong },
    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
+2 −0
Original line number Diff line number Diff line
@@ -456,12 +456,14 @@ sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorS
    if (colorSpace == nullptr) return nullptr;
    if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
        doThrowIAE(env, "The color space must be an RGB color space");
        return nullptr;
    }

    jobject transferParams = env->CallObjectMethod(colorSpace,
            gColorSpaceRGB_getTransferParametersMethodID);
    if (transferParams == nullptr) {
        doThrowIAE(env, "The color space must use an ICC parametric transfer function");
        return nullptr;
    }

    jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
+28 −0
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package android.graphics;

import android.annotation.CheckResult;
import android.annotation.ColorInt;
import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
@@ -1779,6 +1781,30 @@ public final class Bitmap implements Parcelable {
        nativeErase(mNativePtr, c);
    }

    /**
     * Fills the bitmap's pixels with the specified {@link Color}.
     *
     * @throws IllegalStateException if the bitmap is not mutable.
     * @throws IllegalArgumentException if the color space encoded in the long
     *                                  is invalid or unknown.
     *
     * @hide pending API approval
     */
    @TestApi
    public void eraseColor(@ColorLong long c) {
        checkRecycled("Can't erase a recycled bitmap");
        if (!isMutable()) {
            throw new IllegalStateException("cannot erase immutable bitmaps");
        }

        ColorSpace cs = Color.colorSpace(c);
        float r = Color.red(c);
        float g = Color.green(c);
        float b = Color.blue(c);
        float a = Color.alpha(c);
        nativeErase(mNativePtr, cs, r, g, b, a);
    }

    /**
     * Returns the {@link Color} at the specified location. Throws an exception
     * if x or y are out of bounds (negative or >= to the width or height
@@ -2123,6 +2149,8 @@ public final class Bitmap implements Parcelable {
                                            int quality, OutputStream stream,
                                            byte[] tempStorage);
    private static native void nativeErase(long nativeBitmap, int color);
    private static native void nativeErase(long nativeBitmap, ColorSpace cs,
                                           float r, float g, float b, float a);
    private static native int nativeRowBytes(long nativeBitmap);
    private static native int nativeConfig(long nativeBitmap);