diff --git a/packages/react-native/Libraries/Image/Image.d.ts b/packages/react-native/Libraries/Image/Image.d.ts
index 95e42447033..d50679a548b 100644
--- a/packages/react-native/Libraries/Image/Image.d.ts
+++ b/packages/react-native/Libraries/Image/Image.d.ts
@@ -200,6 +200,8 @@ export interface ImagePropsBase
* 'center': Scale the image down so that it is completely visible,
* if bigger than the area of the view.
* The image will not be scaled up.
+ *
+ * 'none': Do not resize the image. The image will be displayed at its intrinsic size.
*/
resizeMode?: ImageResizeMode | undefined;
diff --git a/packages/react-native/Libraries/Image/ImageProps.js b/packages/react-native/Libraries/Image/ImageProps.js
index c0c39075872..80c05862e43 100644
--- a/packages/react-native/Libraries/Image/ImageProps.js
+++ b/packages/react-native/Libraries/Image/ImageProps.js
@@ -19,6 +19,7 @@ import type {
} from '../StyleSheet/StyleSheet';
import type {LayoutEvent, SyntheticEvent} from '../Types/CoreEventTypes';
import typeof Image from './Image';
+import type {ImageResizeMode} from './ImageResizeMode';
import type {ImageSource} from './ImageSource';
import type {ElementRef, Node, RefSetter} from 'react';
@@ -234,7 +235,7 @@ export type ImageProps = $ReadOnly<{|
*
* See https://reactnative.dev/docs/image#resizemode
*/
- resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'),
+ resizeMode?: ?ImageResizeMode,
/**
* A unique identifier for this element to be used in UI Automation
diff --git a/packages/react-native/Libraries/Image/ImageResizeMode.d.ts b/packages/react-native/Libraries/Image/ImageResizeMode.d.ts
index 84174e3da96..5df952b678d 100644
--- a/packages/react-native/Libraries/Image/ImageResizeMode.d.ts
+++ b/packages/react-native/Libraries/Image/ImageResizeMode.d.ts
@@ -12,7 +12,8 @@ export type ImageResizeMode =
| 'contain'
| 'stretch'
| 'repeat'
- | 'center';
+ | 'center'
+ | 'none';
/**
* @see ImageResizeMode.js
@@ -46,4 +47,10 @@ export interface ImageResizeModeStatic {
* image will keep it's size and aspect ratio.
*/
repeat: ImageResizeMode;
+
+ /**
+ * none - The image will be displayed at its intrinsic size, which means the
+ * image will not be scaled up or down.
+ */
+ none: ImageResizeMode;
}
diff --git a/packages/react-native/Libraries/Image/ImageResizeMode.js b/packages/react-native/Libraries/Image/ImageResizeMode.js
index b63627b793b..50001ce552c 100644
--- a/packages/react-native/Libraries/Image/ImageResizeMode.js
+++ b/packages/react-native/Libraries/Image/ImageResizeMode.js
@@ -33,4 +33,7 @@ export type ImageResizeMode =
// Resize by stretching it to fill the entire frame of the view without
// clipping. This may change the aspect ratio of the image, distorting it.
- | 'stretch';
+ | 'stretch'
+
+ // The image will not be resized at all.
+ | 'none';
diff --git a/packages/react-native/Libraries/Image/ImageUtils.js b/packages/react-native/Libraries/Image/ImageUtils.js
index 732b5733bc6..c0e00bb534a 100644
--- a/packages/react-native/Libraries/Image/ImageUtils.js
+++ b/packages/react-native/Libraries/Image/ImageUtils.js
@@ -8,15 +8,18 @@
* @format
*/
-type ResizeMode = 'cover' | 'contain' | 'stretch' | 'repeat' | 'center';
+import type {ImageResizeMode} from './ImageResizeMode';
-const objectFitMap: {[string]: ResizeMode} = {
+const objectFitMap: {[string]: ImageResizeMode} = {
contain: 'contain',
cover: 'cover',
fill: 'stretch',
'scale-down': 'contain',
+ none: 'none',
};
-export function convertObjectFitToResizeMode(objectFit: ?string): ?ResizeMode {
+export function convertObjectFitToResizeMode(
+ objectFit: ?string,
+): ?ImageResizeMode {
return objectFit != null ? objectFitMap[objectFit] : undefined;
}
diff --git a/packages/react-native/Libraries/Image/RCTImageUtils.mm b/packages/react-native/Libraries/Image/RCTImageUtils.mm
index 38fbd6bad43..b7f85f83fc3 100644
--- a/packages/react-native/Libraries/Image/RCTImageUtils.mm
+++ b/packages/react-native/Libraries/Image/RCTImageUtils.mm
@@ -85,6 +85,7 @@ CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTR
switch (resizeMode) {
case RCTResizeModeStretch:
case RCTResizeModeRepeat:
+ case RCTResizeModeNone:
return (CGRect){CGPointZero, RCTCeilSize(destSize, destScale)};
@@ -249,6 +250,7 @@ BOOL RCTUpscalingRequired(
case RCTResizeModeRepeat:
case RCTResizeModeCenter:
+ case RCTResizeModeNone:
return NO;
}
diff --git a/packages/react-native/Libraries/Image/RCTResizeMode.h b/packages/react-native/Libraries/Image/RCTResizeMode.h
index 148e3dd2fe9..e65f113a0dc 100644
--- a/packages/react-native/Libraries/Image/RCTResizeMode.h
+++ b/packages/react-native/Libraries/Image/RCTResizeMode.h
@@ -13,6 +13,7 @@ typedef NS_ENUM(NSInteger, RCTResizeMode) {
RCTResizeModeStretch = UIViewContentModeScaleToFill,
RCTResizeModeCenter = UIViewContentModeCenter,
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
+ RCTResizeModeNone = UIViewContentModeTopLeft,
};
static inline RCTResizeMode RCTResizeModeFromUIViewContentMode(UIViewContentMode mode)
@@ -30,12 +31,14 @@ static inline RCTResizeMode RCTResizeModeFromUIViewContentMode(UIViewContentMode
case UIViewContentModeCenter:
return RCTResizeModeCenter;
break;
+ case UIViewContentModeTopLeft:
+ return RCTResizeModeNone;
+ break;
case UIViewContentModeRedraw:
case UIViewContentModeTop:
case UIViewContentModeBottom:
case UIViewContentModeLeft:
case UIViewContentModeRight:
- case UIViewContentModeTopLeft:
case UIViewContentModeTopRight:
case UIViewContentModeBottomLeft:
case UIViewContentModeBottomRight:
diff --git a/packages/react-native/Libraries/Image/RCTResizeMode.mm b/packages/react-native/Libraries/Image/RCTResizeMode.mm
index c35c32e3fd1..88ea96eb036 100644
--- a/packages/react-native/Libraries/Image/RCTResizeMode.mm
+++ b/packages/react-native/Libraries/Image/RCTResizeMode.mm
@@ -17,6 +17,7 @@ RCT_ENUM_CONVERTER(
@"stretch" : @(RCTResizeModeStretch),
@"center" : @(RCTResizeModeCenter),
@"repeat" : @(RCTResizeModeRepeat),
+ @"none" : @(RCTResizeModeNone),
}),
RCTResizeModeStretch,
integerValue)
diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
index a4aa69d0275..05a8b6410f4 100644
--- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
+++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
@@ -568,6 +568,6 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
overlayColor?: ColorValue | undefined;
tintColor?: ColorValue | undefined;
opacity?: AnimatableNumericValue | undefined;
- objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | undefined;
+ objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none' | undefined;
cursor?: CursorValue | undefined;
}
diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
index ebc1dfa98b0..0d75a942040 100644
--- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
+++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
@@ -11,6 +11,7 @@
'use strict';
import type AnimatedNode from '../Animated/nodes/AnimatedNode';
+import type {ImageResizeMode} from './../Image/ImageResizeMode';
import type {
____DangerouslyImpreciseStyle_InternalOverrides,
____ImageStyle_InternalOverrides,
@@ -941,8 +942,8 @@ export type ____TextStyle_Internal = $ReadOnly<{
export type ____ImageStyle_InternalCore = $ReadOnly<{
...$Exact<____ViewStyle_Internal>,
- resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
- objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down',
+ resizeMode?: ImageResizeMode,
+ objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none',
tintColor?: ____ColorValue_Internal,
overlayColor?: string,
}>;
@@ -954,8 +955,8 @@ export type ____ImageStyle_Internal = $ReadOnly<{
export type ____DangerouslyImpreciseStyle_InternalCore = $ReadOnly<{
...$Exact<____TextStyle_Internal>,
- resizeMode?: 'contain' | 'cover' | 'stretch' | 'center' | 'repeat',
- objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down',
+ resizeMode?: ImageResizeMode,
+ objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | 'none',
tintColor?: ____ColorValue_Internal,
overlayColor?: string,
}>;
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 ceca9bbce45..ea0a2fe12ef 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
@@ -4869,7 +4869,7 @@ export type ImageProps = $ReadOnly<{|
| \\"strict-origin-when-cross-origin\\"
| \\"unsafe-url\\"
),
- resizeMode?: ?(\\"cover\\" | \\"contain\\" | \\"stretch\\" | \\"repeat\\" | \\"center\\"),
+ resizeMode?: ?ImageResizeMode,
testID?: ?string,
tintColor?: ColorValue,
src?: ?string,
@@ -4892,7 +4892,8 @@ exports[`public API should not change unintentionally Libraries/Image/ImageResiz
| \\"contain\\"
| \\"cover\\"
| \\"repeat\\"
- | \\"stretch\\";
+ | \\"stretch\\"
+ | \\"none\\";
"
`;
@@ -4989,10 +4990,9 @@ export type { ImageProps } from \\"./ImageProps\\";
`;
exports[`public API should not change unintentionally Libraries/Image/ImageUtils.js 1`] = `
-"type ResizeMode = \\"cover\\" | \\"contain\\" | \\"stretch\\" | \\"repeat\\" | \\"center\\";
-declare export function convertObjectFitToResizeMode(
+"declare export function convertObjectFitToResizeMode(
objectFit: ?string
-): ?ResizeMode;
+): ?ImageResizeMode;
"
`;
@@ -8261,8 +8261,8 @@ export type ____TextStyle_Internal = $ReadOnly<{
}>;
export type ____ImageStyle_InternalCore = $ReadOnly<{
...$Exact<____ViewStyle_Internal>,
- resizeMode?: \\"contain\\" | \\"cover\\" | \\"stretch\\" | \\"center\\" | \\"repeat\\",
- objectFit?: \\"cover\\" | \\"contain\\" | \\"fill\\" | \\"scale-down\\",
+ resizeMode?: ImageResizeMode,
+ objectFit?: \\"cover\\" | \\"contain\\" | \\"fill\\" | \\"scale-down\\" | \\"none\\",
tintColor?: ____ColorValue_Internal,
overlayColor?: string,
}>;
@@ -8272,8 +8272,8 @@ export type ____ImageStyle_Internal = $ReadOnly<{
}>;
export type ____DangerouslyImpreciseStyle_InternalCore = $ReadOnly<{
...$Exact<____TextStyle_Internal>,
- resizeMode?: \\"contain\\" | \\"cover\\" | \\"stretch\\" | \\"center\\" | \\"repeat\\",
- objectFit?: \\"cover\\" | \\"contain\\" | \\"fill\\" | \\"scale-down\\",
+ resizeMode?: ImageResizeMode,
+ objectFit?: \\"cover\\" | \\"contain\\" | \\"fill\\" | \\"scale-down\\" | \\"none\\",
tintColor?: ____ColorValue_Internal,
overlayColor?: string,
}>;
diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.kt
index 76da29958b1..61098ad9c38 100644
--- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.kt
+++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/image/ImageResizeMode.kt
@@ -19,6 +19,7 @@ public object ImageResizeMode {
private const val RESIZE_MODE_STRETCH = "stretch"
private const val RESIZE_MODE_CENTER = "center"
private const val RESIZE_MODE_REPEAT = "repeat"
+ private const val RESIZE_MODE_NONE = "none"
/** Converts JS resize modes into `ScalingUtils.ScaleType`. See `ImageResizeMode.js`. */
@JvmStatic
@@ -30,6 +31,7 @@ public object ImageResizeMode {
RESIZE_MODE_CENTER -> return ScalingUtils.ScaleType.CENTER_INSIDE
// Handled via a combination of ScaleType and TileMode
RESIZE_MODE_REPEAT -> return ScaleTypeStartInside.INSTANCE
+ RESIZE_MODE_NONE -> return ScaleTypeStartInside.INSTANCE
}
if (resizeModeValue != null) {
@@ -45,7 +47,8 @@ public object ImageResizeMode {
if (RESIZE_MODE_CONTAIN == resizeModeValue ||
RESIZE_MODE_COVER == resizeModeValue ||
RESIZE_MODE_STRETCH == resizeModeValue ||
- RESIZE_MODE_CENTER == resizeModeValue) {
+ RESIZE_MODE_CENTER == resizeModeValue ||
+ RESIZE_MODE_NONE == resizeModeValue) {
return TileMode.CLAMP
}
if (RESIZE_MODE_REPEAT == resizeModeValue) {
diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.kt
index 1c6f98d76ec..c3c589986af 100644
--- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.kt
+++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/views/image/ImageResizeModeTest.kt
@@ -28,6 +28,8 @@ class ImageResizeModeTest {
.isEqualTo(ScalingUtils.ScaleType.FIT_XY)
Assertions.assertThat(ImageResizeMode.toScaleType("center"))
.isEqualTo(ScalingUtils.ScaleType.CENTER_INSIDE)
+ Assertions.assertThat(ImageResizeMode.toScaleType("none"))
+ .isEqualTo(ScaleTypeStartInside.INSTANCE)
// No resizeMode set
Assertions.assertThat(ImageResizeMode.defaultValue())
diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/conversions.h b/packages/react-native/ReactCommon/react/renderer/components/image/conversions.h
index 0a76824f588..2803206c792 100644
--- a/packages/react-native/ReactCommon/react/renderer/components/image/conversions.h
+++ b/packages/react-native/ReactCommon/react/renderer/components/image/conversions.h
@@ -148,6 +148,8 @@ inline void fromRawValue(
result = ImageResizeMode::Center;
} else if (stringValue == "repeat") {
result = ImageResizeMode::Repeat;
+ } else if (stringValue == "none") {
+ result = ImageResizeMode::None;
} else {
LOG(ERROR) << "Unsupported ImageResizeMode value: " << stringValue;
react_native_expect(false);
@@ -168,6 +170,8 @@ inline std::string toString(const ImageResizeMode& value) {
return "center";
case ImageResizeMode::Repeat:
return "repeat";
+ case ImageResizeMode::None:
+ return "none";
}
}
diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/RCTImagePrimitivesConversions.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/RCTImagePrimitivesConversions.h
index 88487f94d48..50194b7a754 100644
--- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/RCTImagePrimitivesConversions.h
+++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/RCTImagePrimitivesConversions.h
@@ -26,6 +26,8 @@ inline static UIViewContentMode RCTContentModeFromImageResizeMode(facebook::reac
// Repeat resize mode is handled by the UIImage. Use scale to fill
// so the repeated image fills the UIImageView.
return UIViewContentModeScaleToFill;
+ case facebook::react::ImageResizeMode::None:
+ return UIViewContentModeTopLeft;
}
}
@@ -42,6 +44,8 @@ inline std::string toString(const facebook::react::ImageResizeMode &value)
return "center";
case facebook::react::ImageResizeMode::Repeat:
return "repeat";
+ case facebook::react::ImageResizeMode::None:
+ return "none";
}
}
diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/primitives.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/primitives.h
index 18aba9e10b5..e8d4be21db4 100644
--- a/packages/react-native/ReactCommon/react/renderer/imagemanager/primitives.h
+++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/primitives.h
@@ -47,6 +47,7 @@ enum class ImageResizeMode {
Stretch,
Center,
Repeat,
+ None,
};
class ImageErrorInfo {
diff --git a/packages/rn-tester/js/examples/Image/ImageExample.js b/packages/rn-tester/js/examples/Image/ImageExample.js
index 81e42ad8adb..b3dddd83e87 100644
--- a/packages/rn-tester/js/examples/Image/ImageExample.js
+++ b/packages/rn-tester/js/examples/Image/ImageExample.js
@@ -825,6 +825,9 @@ const styles = StyleSheet.create({
objectFitScaleDown: {
objectFit: 'scale-down',
},
+ objectFitNone: {
+ objectFit: 'none',
+ },
imageInBundle: {
borderColor: 'yellow',
borderWidth: 4,
@@ -1466,6 +1469,17 @@ exports.examples = [
/>
+
+
+
+ None
+
+
+
+
);
})}
@@ -1537,6 +1551,18 @@ exports.examples = [
/>
+
+
+
+ None
+
+
+
+
);
})}