From b1c20eea9e53c2ae1147ce44ed25e524a4e51cc1 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 7 Jun 2023 17:58:16 -0400 Subject: Transform & preserve gainmaps Have Bitmap.createBitmap(sourceBitmap, ...) preserve any gainmaps if present, transforming the gainmaps in the same way. This addresses 2 common usages: 1) Rotating bitmaps to handle EXIF orientations 2) Bitmap.createScaledBitmap() to do "static" scaling Bug: 286131154 Test: SilkFX GainmapTransformsTest Change-Id: I5a62dccbb2c70bc38cca581b161eef792c8b2a78 --- graphics/java/android/graphics/Bitmap.java | 51 +++++++++++++++++++++++++++++ graphics/java/android/graphics/Gainmap.java | 11 +++++++ 2 files changed, 62 insertions(+) (limited to 'graphics/java/android') diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 2307d6080f9f..b9d3756ac6d2 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -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 diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java index 9ac84a6159da..f639521ff250 100644 --- a/graphics/java/android/graphics/Gainmap.java +++ b/graphics/java/android/graphics/Gainmap.java @@ -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 @@ -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); -- cgit v1.2.3-59-g8ed1b