Loading graphics/java/android/graphics/Bitmap.java +51 −0 Original line number Diff line number Diff line Loading @@ -997,12 +997,63 @@ public final class Bitmap implements Parcelable { canvas.concat(m); canvas.drawBitmap(source, srcR, dstR, paint); canvas.setBitmap(null); // If the source has a gainmap, apply the same set of transformations to the gainmap // and set it on the output if (source.hasGainmap()) { Bitmap newMapContents = transformGainmap(source, m, neww, newh, paint, srcR, dstR, deviceR); if (newMapContents != null) { bitmap.setGainmap(new Gainmap(source.getGainmap(), newMapContents)); } } if (isHardware) { return bitmap.copy(Config.HARDWARE, false); } return bitmap; } private static Bitmap transformGainmap(Bitmap source, Matrix m, int neww, int newh, Paint paint, Rect srcR, RectF dstR, RectF deviceR) { Canvas canvas; Bitmap sourceGainmap = source.getGainmap().getGainmapContents(); // Gainmaps can be scaled relative to the base image (eg, 1/4th res) // Preserve that relative scaling between the base & gainmap in the output float scaleX = (sourceGainmap.getWidth() / (float) source.getWidth()); float scaleY = (sourceGainmap.getHeight() / (float) source.getHeight()); int mapw = Math.round(neww * scaleX); int maph = Math.round(newh * scaleY); if (mapw == 0 || maph == 0) { // The gainmap has been scaled away entirely, drop it return null; } // Scale the computed `srcR` used for rendering the source bitmap to the destination // to be in gainmap dimensions Rect gSrcR = new Rect((int) (srcR.left * scaleX), (int) (srcR.top * scaleY), (int) (srcR.right * scaleX), (int) (srcR.bottom * scaleY)); // Note: createBitmap isn't used as that requires a non-null colorspace, however // gainmaps don't have a colorspace. So use `nativeCreate` directly to bypass // that colorspace enforcement requirement (#getColorSpace() allows a null return) Bitmap newMapContents = nativeCreate(null, 0, mapw, mapw, maph, sourceGainmap.getConfig().nativeInt, true, 0); newMapContents.eraseColor(0); canvas = new Canvas(newMapContents); // Scale the translate & matrix to be in gainmap-relative dimensions canvas.scale(scaleX, scaleY); canvas.translate(-deviceR.left, -deviceR.top); canvas.concat(m); canvas.drawBitmap(sourceGainmap, gSrcR, dstR, paint); canvas.setBitmap(null); // Create a new gainmap using a copy of the metadata information from the source but // with the transformed bitmap created above return newMapContents; } /** * Returns a mutable bitmap with the specified width and height. Its * initial density is as per {@link #getDensity}. The newly created Loading graphics/java/android/graphics/Gainmap.java +11 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,16 @@ public final class Gainmap implements Parcelable { this(gainmapContents, nCreateEmpty()); } /** * Creates a new gainmap using the provided gainmap as the metadata source and the provided * bitmap as the replacement for the gainmapContents * TODO: Make public, it's useful * @hide */ public Gainmap(@NonNull Gainmap gainmap, @NonNull Bitmap gainmapContents) { this(gainmapContents, nCreateCopy(gainmap.mNativePtr)); } /** * @return Returns the image data of the gainmap represented as a Bitmap. This is represented * as a Bitmap for broad API compatibility, however certain aspects of the Bitmap are ignored Loading Loading @@ -325,6 +335,7 @@ public final class Gainmap implements Parcelable { private static native long nGetFinalizer(); private static native long nCreateEmpty(); private static native long nCreateCopy(long source); private static native void nSetBitmap(long ptr, Bitmap bitmap); Loading libs/hwui/jni/Gainmap.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,16 @@ jlong Gainmap_createEmpty(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap)); } jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) { Gainmap* gainmap = new Gainmap(); gainmap->incStrong(0); if (sourcePtr) { Gainmap* src = fromJava(sourcePtr); gainmap->info = src->info; } return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap)); } static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) { android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap); fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap); Loading Loading @@ -237,6 +247,7 @@ static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, job static const JNINativeMethod gGainmapMethods[] = { {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer}, {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty}, {"nCreateCopy", "(J)J", (void*)Gainmap_createCopy}, {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap}, {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin}, {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin}, Loading tests/SilkFX/res/layout/gainmap_transform_test.xml 0 → 100644 +122 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <com.android.test.silkfx.hdr.GainmapTransformsTest xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/original" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Original" /> <Button android:id="@+id/scaled" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Scaled (1/3)" /> <Button android:id="@+id/rotate_90" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Rotate 90" /> <Button android:id="@+id/rotate_90_scaled" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Rot90+Scale" /> <Button android:id="@+id/crop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Crop" /> <Button android:id="@+id/crop_200" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Crop 200" /> </LinearLayout> <TextView android:id="@+id/source_info" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1"> <TextView android:id="@+id/sdr_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/sdr_source" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:scaleType="fitStart" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1"> <TextView android:id="@+id/gainmap_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/gainmap" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:scaleType="fitStart" /> </LinearLayout> </LinearLayout> </com.android.test.silkfx.hdr.GainmapTransformsTest> No newline at end of file tests/SilkFX/src/com/android/test/silkfx/Main.kt +3 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,9 @@ private val AllDemos = listOf( Demo("Color Grid", R.layout.color_grid), Demo("Gradient Sweep", R.layout.gradient_sweep), Demo("Gainmap Image", R.layout.gainmap_image), Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false) Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false), Demo("Gainmap Transform Test", R.layout.gainmap_transform_test, commonControls = false) )), DemoGroup("Materials", listOf( Demo("Glass", GlassActivity::class), Loading Loading
graphics/java/android/graphics/Bitmap.java +51 −0 Original line number Diff line number Diff line Loading @@ -997,12 +997,63 @@ public final class Bitmap implements Parcelable { canvas.concat(m); canvas.drawBitmap(source, srcR, dstR, paint); canvas.setBitmap(null); // If the source has a gainmap, apply the same set of transformations to the gainmap // and set it on the output if (source.hasGainmap()) { Bitmap newMapContents = transformGainmap(source, m, neww, newh, paint, srcR, dstR, deviceR); if (newMapContents != null) { bitmap.setGainmap(new Gainmap(source.getGainmap(), newMapContents)); } } if (isHardware) { return bitmap.copy(Config.HARDWARE, false); } return bitmap; } private static Bitmap transformGainmap(Bitmap source, Matrix m, int neww, int newh, Paint paint, Rect srcR, RectF dstR, RectF deviceR) { Canvas canvas; Bitmap sourceGainmap = source.getGainmap().getGainmapContents(); // Gainmaps can be scaled relative to the base image (eg, 1/4th res) // Preserve that relative scaling between the base & gainmap in the output float scaleX = (sourceGainmap.getWidth() / (float) source.getWidth()); float scaleY = (sourceGainmap.getHeight() / (float) source.getHeight()); int mapw = Math.round(neww * scaleX); int maph = Math.round(newh * scaleY); if (mapw == 0 || maph == 0) { // The gainmap has been scaled away entirely, drop it return null; } // Scale the computed `srcR` used for rendering the source bitmap to the destination // to be in gainmap dimensions Rect gSrcR = new Rect((int) (srcR.left * scaleX), (int) (srcR.top * scaleY), (int) (srcR.right * scaleX), (int) (srcR.bottom * scaleY)); // Note: createBitmap isn't used as that requires a non-null colorspace, however // gainmaps don't have a colorspace. So use `nativeCreate` directly to bypass // that colorspace enforcement requirement (#getColorSpace() allows a null return) Bitmap newMapContents = nativeCreate(null, 0, mapw, mapw, maph, sourceGainmap.getConfig().nativeInt, true, 0); newMapContents.eraseColor(0); canvas = new Canvas(newMapContents); // Scale the translate & matrix to be in gainmap-relative dimensions canvas.scale(scaleX, scaleY); canvas.translate(-deviceR.left, -deviceR.top); canvas.concat(m); canvas.drawBitmap(sourceGainmap, gSrcR, dstR, paint); canvas.setBitmap(null); // Create a new gainmap using a copy of the metadata information from the source but // with the transformed bitmap created above return newMapContents; } /** * Returns a mutable bitmap with the specified width and height. Its * initial density is as per {@link #getDensity}. The newly created Loading
graphics/java/android/graphics/Gainmap.java +11 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,16 @@ public final class Gainmap implements Parcelable { this(gainmapContents, nCreateEmpty()); } /** * Creates a new gainmap using the provided gainmap as the metadata source and the provided * bitmap as the replacement for the gainmapContents * TODO: Make public, it's useful * @hide */ public Gainmap(@NonNull Gainmap gainmap, @NonNull Bitmap gainmapContents) { this(gainmapContents, nCreateCopy(gainmap.mNativePtr)); } /** * @return Returns the image data of the gainmap represented as a Bitmap. This is represented * as a Bitmap for broad API compatibility, however certain aspects of the Bitmap are ignored Loading Loading @@ -325,6 +335,7 @@ public final class Gainmap implements Parcelable { private static native long nGetFinalizer(); private static native long nCreateEmpty(); private static native long nCreateCopy(long source); private static native void nSetBitmap(long ptr, Bitmap bitmap); Loading
libs/hwui/jni/Gainmap.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -86,6 +86,16 @@ jlong Gainmap_createEmpty(JNIEnv*, jobject) { return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap)); } jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) { Gainmap* gainmap = new Gainmap(); gainmap->incStrong(0); if (sourcePtr) { Gainmap* src = fromJava(sourcePtr); gainmap->info = src->info; } return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap)); } static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) { android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap); fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap); Loading Loading @@ -237,6 +247,7 @@ static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, job static const JNINativeMethod gGainmapMethods[] = { {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer}, {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty}, {"nCreateCopy", "(J)J", (void*)Gainmap_createCopy}, {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap}, {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin}, {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin}, Loading
tests/SilkFX/res/layout/gainmap_transform_test.xml 0 → 100644 +122 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2023 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. ~ You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, software ~ distributed under the License is distributed on an "AS IS" BASIS, ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ~ See the License for the specific language governing permissions and ~ limitations under the License. --> <com.android.test.silkfx.hdr.GainmapTransformsTest xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/original" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Original" /> <Button android:id="@+id/scaled" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Scaled (1/3)" /> <Button android:id="@+id/rotate_90" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Rotate 90" /> <Button android:id="@+id/rotate_90_scaled" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Rot90+Scale" /> <Button android:id="@+id/crop" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Crop" /> <Button android:id="@+id/crop_200" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="Crop 200" /> </LinearLayout> <TextView android:id="@+id/source_info" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1"> <TextView android:id="@+id/sdr_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/sdr_source" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:scaleType="fitStart" /> </LinearLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_weight="1"> <TextView android:id="@+id/gainmap_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <ImageView android:id="@+id/gainmap" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dp" android:scaleType="fitStart" /> </LinearLayout> </LinearLayout> </com.android.test.silkfx.hdr.GainmapTransformsTest> No newline at end of file
tests/SilkFX/src/com/android/test/silkfx/Main.kt +3 −1 Original line number Diff line number Diff line Loading @@ -55,7 +55,9 @@ private val AllDemos = listOf( Demo("Color Grid", R.layout.color_grid), Demo("Gradient Sweep", R.layout.gradient_sweep), Demo("Gainmap Image", R.layout.gainmap_image), Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false) Demo("Gainmap Decode Test", R.layout.gainmap_decode_test, commonControls = false), Demo("Gainmap Transform Test", R.layout.gainmap_transform_test, commonControls = false) )), DemoGroup("Materials", listOf( Demo("Glass", GlassActivity::class), Loading