diff --git a/packages/react-native/Libraries/Image/ImageProps.js b/packages/react-native/Libraries/Image/ImageProps.js index 7f3166d4de02d8..3b62af9fcdcfec 100644 --- a/packages/react-native/Libraries/Image/ImageProps.js +++ b/packages/react-native/Libraries/Image/ImageProps.js @@ -59,6 +59,22 @@ type AndroidImageProps = $ReadOnly<{| loadingIndicatorSource?: ?(number | $ReadOnly<{|uri: string|}>), progressiveRenderingEnabled?: ?boolean, fadeDuration?: ?number, + + /** + * The mechanism that should be used to resize the image when the image's + * dimensions differ from the image view's dimensions. Defaults to `'auto'`. + * See https://reactnative.dev/docs/image#resizemethod-android + */ + resizeMethod?: ?('auto' | 'resize' | 'scale'), + + /** + * When the `resizeMethod` is set to `resize`, the destination dimensions are + * multiplied by this value. The `scale` method is used to perform the + * remainder of the resize. + * This is used to produce higher quality images when resizing to small dimensions. + * Defaults to 1.0. + */ + resizeMultiplier?: ?number, |}>; export type ImageProps = {| @@ -183,11 +199,6 @@ export type ImageProps = {| */ onLoadStart?: ?() => void, - /** - * See https://reactnative.dev/docs/image#resizemethod - */ - resizeMethod?: ?('auto' | 'resize' | 'scale'), - /** * The image source (either a remote URL or a local file resource). * diff --git a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js b/packages/react-native/Libraries/Image/ImageViewNativeComponent.js index 01459dddc053d1..0dc98c6407273d 100644 --- a/packages/react-native/Libraries/Image/ImageViewNativeComponent.js +++ b/packages/react-native/Libraries/Image/ImageViewNativeComponent.js @@ -82,13 +82,14 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = validAttributes: { blurRadius: true, internal_analyticTag: true, + resizeMethod: true, resizeMode: true, + resizeMultiplier: true, tintColor: { process: require('../StyleSheet/processColor').default, }, borderBottomLeftRadius: true, borderTopLeftRadius: true, - resizeMethod: true, src: true, // NOTE: New Architecture expects this to be called `source`, // regardless of the platform, therefore propagate it as well. diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index f270fe7529ead5..9ef6b99d40414a 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -4445,6 +4445,8 @@ type AndroidImageProps = $ReadOnly<{| loadingIndicatorSource?: ?(number | $ReadOnly<{| uri: string |}>), progressiveRenderingEnabled?: ?boolean, fadeDuration?: ?number, + resizeMethod?: ?(\\"auto\\" | \\"resize\\" | \\"scale\\"), + resizeMultiplier?: ?number, |}>; export type ImageProps = {| ...$Diff>, @@ -4472,7 +4474,6 @@ export type ImageProps = {| onLoad?: ?(event: ImageLoadEvent) => void, onLoadEnd?: ?() => void, onLoadStart?: ?() => void, - resizeMethod?: ?(\\"auto\\" | \\"resize\\" | \\"scale\\"), source?: ?ImageSource, style?: ?ImageStyleProp, referrerPolicy?: ?( diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 7058755cfc3333..582ef18f982de2 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -6390,6 +6390,7 @@ public class com/facebook/react/views/image/ReactImageManager : com/facebook/rea public fun setProgressiveRenderingEnabled (Lcom/facebook/react/views/image/ReactImageView;Z)V public fun setResizeMethod (Lcom/facebook/react/views/image/ReactImageView;Ljava/lang/String;)V public fun setResizeMode (Lcom/facebook/react/views/image/ReactImageView;Ljava/lang/String;)V + public fun setResizeMultiplier (Lcom/facebook/react/views/image/ReactImageView;F)V public fun setSource (Lcom/facebook/react/views/image/ReactImageView;Lcom/facebook/react/bridge/ReadableArray;)V public fun setSrc (Lcom/facebook/react/views/image/ReactImageView;Lcom/facebook/react/bridge/ReadableArray;)V public fun setTintColor (Lcom/facebook/react/views/image/ReactImageView;Ljava/lang/Integer;)V @@ -6423,6 +6424,7 @@ public class com/facebook/react/views/image/ReactImageView : com/facebook/drawee public fun setOverlayColor (I)V public fun setProgressiveRenderingEnabled (Z)V public fun setResizeMethod (Lcom/facebook/react/views/image/ImageResizeMethod;)V + public fun setResizeMultiplier (F)V public fun setScaleType (Lcom/facebook/drawee/drawable/ScalingUtils$ScaleType;)V public fun setShouldNotifyLoadEvents (Z)V public fun setSource (Lcom/facebook/react/bridge/ReadableArray;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMethod.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMethod.kt index 3e5f252fac37cc..4cd3e8425a615d 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMethod.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMethod.kt @@ -10,5 +10,5 @@ package com.facebook.react.views.image public enum class ImageResizeMethod { AUTO, RESIZE, - SCALE + SCALE, } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java index 772c4de78d7749..ec5f5cecc7c743 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java @@ -223,6 +223,14 @@ public void setResizeMethod(ReactImageView view, @Nullable String resizeMethod) } } + @ReactProp(name = "resizeMultiplier") + public void setResizeMultiplier(ReactImageView view, float resizeMultiplier) { + if (resizeMultiplier < 0.01f) { + FLog.w(ReactConstants.TAG, "Invalid resize multiplier: '" + resizeMultiplier + "'"); + } + view.setResizeMultiplier(resizeMultiplier); + } + @ReactProp(name = "tintColor", customType = "Color") public void setTintColor(ReactImageView view, @Nullable Integer tintColor) { if (tintColor == null) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java index 92001e55fb1a65..d02b91663b769a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java @@ -134,6 +134,7 @@ public CloseableReference process(Bitmap source, PlatformBitmapFactory b private int mFadeDurationMs = -1; private boolean mProgressiveRenderingEnabled; private ReadableMap mHeaders; + private float mResizeMultiplier = 1.0f; // We can't specify rounding in XML, so have to do so here private static GenericDraweeHierarchy buildHierarchy(Context context) { @@ -307,6 +308,14 @@ public void setResizeMethod(ImageResizeMethod resizeMethod) { } } + public void setResizeMultiplier(float multiplier) { + boolean isNewMultiplier = Math.abs(mResizeMultiplier - multiplier) > 0.0001f; + if (isNewMultiplier) { + mResizeMultiplier = multiplier; + mIsDirty = true; + } + } + public void setSource(@Nullable ReadableArray sources) { List tmpSources = new LinkedList<>(); @@ -478,7 +487,7 @@ public void maybeUpdateView() { } Postprocessor postprocessor = MultiPostprocessor.from(postprocessors); - ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null; + ResizeOptions resizeOptions = doResize ? getResizeOptions() : null; ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri()) @@ -601,6 +610,16 @@ private boolean shouldResize(ImageSource imageSource) { } } + @Nullable + private ResizeOptions getResizeOptions() { + int width = Math.round((float) getWidth() * mResizeMultiplier); + int height = Math.round((float) getHeight() * mResizeMultiplier); + if (width <= 0 || height <= 0) { + return null; + } + return new ResizeOptions(width, height); + } + private void warnImageSource(String uri) { // TODO(T189014077): This code-path produces an infinite loop of js calls with logbox. // This is an issue with Fabric view preallocation, react, and LogBox. Fix.