Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions Libraries/Image/Image.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,24 @@ let Image = (props: ImagePropsType, forwardedRef) => {
source = null;
}

let style;
let sources;
if (source?.uri != null) {
const {width, height} = source;
style = flattenStyle([{width, height}, styles.base, props.style]);
sources = [{uri: source.uri}];
} else {
style = flattenStyle([styles.base, props.style]);
sources = source;
}
const sourceIsSingleImage = !Array.isArray(source) && source != null;
const style = flattenStyle([
sourceIsSingleImage && {
width: source.width,
height: source.height,
},
styles.base,
props.style,
]);

const {onLoadStart, onLoad, onLoadEnd, onError} = props;
const nativeProps = {
...props,
style,
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError),
src: sources,
src: sourceIsSingleImage ? [source] : source,
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
* when making Flow check .android.js files. */
headers: source?.headers,
defaultSrc: defaultSource ? defaultSource.uri : null,
loadingIndicatorSrc: loadingIndicatorSource
? loadingIndicatorSource.uri
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ rn_android_library(
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/modules/fresco:fresco"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/views/imagehelper:imagehelper"),
react_native_target("java/com/facebook/react/views/imagehelper:imagesource"),
react_native_target("java/com/facebook/react/views/image:image"),
],
exported_deps = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,51 +96,7 @@ private ImagePipeline getImagePipeline() {
*/
@ReactMethod
public void getSize(final String uriString, final Promise promise) {
if (uriString == null || uriString.isEmpty()) {
promise.reject(ERROR_INVALID_URI, "Cannot get the size of an image for an empty URI");
return;
}

ImageSource source = new ImageSource(getReactApplicationContext(), uriString);
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(source.getUri()).build();

DataSource<CloseableReference<CloseableImage>> dataSource =
getImagePipeline().fetchDecodedImage(request, getCallerContext());

DataSubscriber<CloseableReference<CloseableImage>> dataSubscriber =
new BaseDataSubscriber<CloseableReference<CloseableImage>>() {
@Override
protected void onNewResultImpl(
DataSource<CloseableReference<CloseableImage>> dataSource) {
if (!dataSource.isFinished()) {
return;
}
CloseableReference<CloseableImage> ref = dataSource.getResult();
if (ref != null) {
try {
CloseableImage image = ref.get();

WritableMap sizes = Arguments.createMap();
sizes.putInt("width", image.getWidth());
sizes.putInt("height", image.getHeight());

promise.resolve(sizes);
} catch (Exception e) {
promise.reject(ERROR_GET_SIZE_FAILURE, e);
} finally {
CloseableReference.closeSafely(ref);
}
} else {
promise.reject(ERROR_GET_SIZE_FAILURE);
}
}

@Override
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
promise.reject(ERROR_GET_SIZE_FAILURE, dataSource.getFailureCause());
}
};
dataSource.subscribe(dataSubscriber, CallerThreadExecutor.getInstance());
getSizeWithHeaders(uriString, null, promise);
}

/**
Expand All @@ -159,11 +115,8 @@ public void getSizeWithHeaders(
return;
}

ImageSource source = new ImageSource(getReactApplicationContext(), uriString);
ImageRequestBuilder imageRequestBuilder =
ImageRequestBuilder.newBuilderWithSource(source.getUri());
ImageRequest request =
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, headers);
ImageSource source = new ImageSource(getReactApplicationContext(), uriString, headers);
ImageRequest request = source.createImageRequest();

DataSource<CloseableReference<CloseableImage>> dataSource =
getImagePipeline().fetchDecodedImage(request, getCallerContext());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ rn_android_library(
react_native_target("java/com/facebook/react/modules/fresco:fresco"),
react_native_target("java/com/facebook/react/uimanager/annotations:annotations"),
react_native_target("java/com/facebook/react/views/imagehelper:withmultisource"),
react_native_target("java/com/facebook/react/views/imagehelper:imagesource"),
],
exported_deps = [
":imageevents",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,6 @@ public void setLoadHandlersRegistered(ReactImageView view, boolean shouldNotifyL
view.setShouldNotifyLoadEvents(shouldNotifyLoadEvents);
}

@ReactProp(name = "headers")
public void setHeaders(ReactImageView view, ReadableMap headers) {
view.setHeaders(headers);
}

@Override
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ public CloseableReference<Bitmap> process(Bitmap source, PlatformBitmapFactory b
private @Nullable Object mCallerContext;
private int mFadeDurationMs = -1;
private boolean mProgressiveRenderingEnabled;
private ReadableMap mHeaders;

// We can't specify rounding in XML, so have to do so here
private static GenericDraweeHierarchy buildHierarchy(Context context) {
Expand Down Expand Up @@ -385,14 +384,15 @@ public void setSource(@Nullable ReadableArray sources) {
List<ImageSource> tmpSources = new LinkedList<>();

if (sources == null || sources.size() == 0) {
ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI);
ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI, null);
tmpSources.add(imageSource);
} else {
// Optimize for the case where we have just one uri, case in which we don't need the sizes
if (sources.size() == 1) {
ReadableMap source = sources.getMap(0);
String uri = source.getString("uri");
ImageSource imageSource = new ImageSource(getContext(), uri);
ReadableMap headers = source.getMap("headers");
ImageSource imageSource = new ImageSource(getContext(), uri, headers);
tmpSources.add(imageSource);
if (Uri.EMPTY.equals(imageSource.getUri())) {
warnImageSource(uri);
Expand All @@ -401,9 +401,10 @@ public void setSource(@Nullable ReadableArray sources) {
for (int idx = 0; idx < sources.size(); idx++) {
ReadableMap source = sources.getMap(idx);
String uri = source.getString("uri");
ReadableMap headers = source.getMap("headers");
ImageSource imageSource =
new ImageSource(
getContext(), uri, source.getDouble("width"), source.getDouble("height"));
getContext(), uri, headers, source.getDouble("width"), source.getDouble("height"));
tmpSources.add(imageSource);
if (Uri.EMPTY.equals(imageSource.getUri())) {
warnImageSource(uri);
Expand Down Expand Up @@ -475,10 +476,6 @@ private void getCornerRadii(float[] computedCorners) {
: defaultBorderRadius;
}

public void setHeaders(ReadableMap headers) {
mHeaders = headers;
}

public void maybeUpdateView() {
if (!mIsDirty) {
return;
Expand Down Expand Up @@ -561,14 +558,14 @@ public void maybeUpdateView() {
ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null;

ImageRequestBuilder imageRequestBuilder =
ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri())
mImageSource.createImageRequestBuilder()
.setPostprocessor(postprocessor)
.setResizeOptions(resizeOptions)
.setAutoRotateEnabled(true)
.setProgressiveRenderingEnabled(mProgressiveRenderingEnabled);

ImageRequest imageRequest =
ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
mImageSource.createImageRequestFromBuilder(imageRequestBuilder);

if (mGlobalImageLoadListener != null) {
mGlobalImageLoadListener.onLoadAttempt(mImageSource.getUri());
Expand All @@ -585,7 +582,7 @@ public void maybeUpdateView() {

if (mCachedImageSource != null) {
ImageRequest cachedImageRequest =
ImageRequestBuilder.newBuilderWithSource(mCachedImageSource.getUri())
mCachedImageSource.createImageRequestBuilder()
.setPostprocessor(postprocessor)
.setResizeOptions(resizeOptions)
.setAutoRotateEnabled(true)
Expand Down Expand Up @@ -656,7 +653,7 @@ private boolean shouldUseRoundedCornerPostprocessing() {
private void setSourceImage() {
mImageSource = null;
if (mSources.isEmpty()) {
ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI);
ImageSource imageSource = new ImageSource(getContext(), REMOTE_TRANSPARENT_BITMAP_URI, null);
mSources.add(imageSource);
} else if (hasMultipleSources()) {
MultiSourceResult multiSource =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ rn_android_library(
name = "imagehelper",
srcs = glob(
["*.java"],
exclude = ["MultiSourceHelper.java"],
exclude = ["MultiSourceHelper.java","ImageSource.java"],
),
autoglob = False,
is_androidx = True,
Expand Down Expand Up @@ -38,3 +38,22 @@ rn_android_library(
":imagehelper",
],
)

rn_android_library(
name = "imagesource",
srcs = ["ImageSource.java"],
autoglob = False,
is_androidx = True,
labels = ["supermodule:xplat/default/public.react_native.infra"],
visibility = [
"PUBLIC",
],
deps = [
react_native_dep("third-party/android/androidx:annotation"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/modules/fresco:fresco"),
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,27 @@
import android.content.Context;
import android.net.Uri;
import androidx.annotation.Nullable;

import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.modules.fresco.ReactNetworkImageRequest;

import java.util.Objects;

/** Class describing an image source (network URI or resource) and size. */
public class ImageSource {

private @Nullable Uri mUri;
private String mSource;
private double mSize;
private final @Nullable Uri mUri;
private final ReadableMap mHeaders;
private final String mSource;
private final double mSize;
private boolean isResource;

public ImageSource(Context context, String source, double width, double height) {
public ImageSource(Context context, String source, ReadableMap headers, double width, double height) {
mSource = source;
mHeaders = headers;
mSize = width * height;

// Important: we compute the URI here so that we don't need to hold a reference to the context,
Expand All @@ -46,8 +54,27 @@ public int hashCode() {
return Objects.hash(mUri, mSource, mSize, isResource);
}

public ImageSource(Context context, String source, ReadableMap headers) {
this(context, source, headers, 0.0d, 0.0d);
}

/** @deprecated for library backwards compatibility only */
public ImageSource(Context context, String source) {
this(context, source, 0.0d, 0.0d);
this(context, source, null);
}

public ImageRequestBuilder createImageRequestBuilder() {
return ImageRequestBuilder.newBuilderWithSource(getUri());
}

public ImageRequest createImageRequestFromBuilder(final ImageRequestBuilder imageRequestBuilder) {
return ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
}

public ImageRequest createImageRequest() {
return createImageRequestFromBuilder(
createImageRequestBuilder()
);
}

/** Get the source of this image, as it was passed to the constructor. */
Expand Down