Enable developers to force Fresco to resize an image

Summary:
Here's a little background. Resizing is inferior to scaling. See http://frescolib.org/docs/resizing-rotating.html#_

Currently, React Native has a heuristic to use resize when the image is likely to be from the device's camera. However, there may be other cases where a developer wants to use resize. For example, when the developer knows they'll be downloading a large image from a service but the image will be rendered at a small size on the device.

This change adds a `resizeMethod` prop to the `Image` component so developers can choose how Fresco resizes the image. The options are 'auto', 'resize', or 'scale'. When 'auto' is specified, a heuristic is used to choose between 'resize' and 'scale'. The default value is 'auto'.

**Test plan (required)**

In a small test app, verified that the `resizeMethod` prop properly influences the mechanism that is used to resize the image (e.g. resize or scale).

Adam Comella
Microsoft Corp.
Closes https://github.com/facebook/react-native/pull/9652

Differential Revision: D3841322

Pulled By: foghina

fbshipit-source-id: 6c78b5c75ea73053aa10386afd4cbff45f5b8ffe
This commit is contained in:
Adam Comella 2016-09-09 05:00:52 -07:00 committed by Facebook Github Bot
parent ea5b335351
commit b6735f3391
6 changed files with 88 additions and 4 deletions

View File

@ -65,6 +65,7 @@ function generateRequestId() {
var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
src: true,
loadingIndicatorSrc: true,
resizeMethod: true,
resizeMode: true,
progressiveRenderingEnabled: true,
fadeDuration: true,
@ -130,6 +131,26 @@ var Image = React.createClass({
* Used to locate this view in end-to-end tests.
*/
testID: PropTypes.string,
/**
* 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`.
*
* - `auto`: Use heuristics to pick between `resize` and `scale`.
*
* - `resize`: A software operation which changes the encoded image in memory before it
* gets decoded. This should be used instead of `scale` when the image is much larger
* than the view.
*
* - `scale`: The image gets drawn downscaled or upscaled. Compared to `resize`, `scale` is
* faster (usually hardware accelerated) and produces higher quality images. This
* should be used if the image is smaller than the view. It should also be used if the
* image is slightly bigger than the view.
*
* More details about `resize` and `scale` can be found at http://frescolib.org/docs/resizing-rotating.html.
*
* @platform android
*/
resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']),
/**
* Determines how to resize the image when the frame doesn't match the raw
* image dimensions.

View File

@ -192,6 +192,26 @@ const Image = React.createClass({
* @platform ios
*/
capInsets: EdgeInsetsPropType,
/**
* 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`.
*
* - `auto`: Use heuristics to pick between `resize` and `scale`.
*
* - `resize`: A software operation which changes the encoded image in memory before it
* gets decoded. This should be used instead of `scale` when the image is much larger
* than the view.
*
* - `scale`: The image gets drawn downscaled or upscaled. Compared to `resize`, `scale` is
* faster (usually hardware accelerated) and produces higher quality images. This
* should be used if the image is smaller than the view. It should also be used if the
* image is slightly bigger than the view.
*
* More details about `resize` and `scale` can be found at http://frescolib.org/docs/resizing-rotating.html.
*
* @platform android
*/
resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']),
/**
* Determines how to resize the image when the frame doesn't match the raw
* image dimensions.

View File

@ -78,6 +78,7 @@ public class ViewProps {
public static final String ELLIPSIZE_MODE = "ellipsizeMode";
public static final String ON = "on";
public static final String RESIZE_MODE = "resizeMode";
public static final String RESIZE_METHOD = "resizeMethod";
public static final String TEXT_ALIGN = "textAlign";
public static final String TEXT_ALIGN_VERTICAL = "textAlignVertical";
public static final String TEXT_DECORATION_LINE = "textDecorationLine";

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.views.image;
public enum ImageResizeMethod {
AUTO,
RESIZE,
SCALE
}

View File

@ -19,6 +19,7 @@ import android.graphics.PorterDuff.Mode;
import com.facebook.csslayout.CSSConstants;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.PixelUtil;
@ -131,6 +132,19 @@ public class ReactImageManager extends SimpleViewManager<ReactImageView> {
view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
}
@ReactProp(name = ViewProps.RESIZE_METHOD)
public void setResizeMethod(ReactImageView view, @Nullable String resizeMethod) {
if (resizeMethod == null || "auto".equals(resizeMethod)) {
view.setResizeMethod(ImageResizeMethod.AUTO);
} else if ("resize".equals(resizeMethod)) {
view.setResizeMethod(ImageResizeMethod.RESIZE);
} else if ("scale".equals(resizeMethod)) {
view.setResizeMethod(ImageResizeMethod.SCALE);
} else {
throw new JSApplicationIllegalArgumentException("Invalid resize method: '" + resizeMethod+ "'");
}
}
@ReactProp(name = "tintColor", customType = "Color")
public void setTintColor(ReactImageView view, @Nullable Integer tintColor) {
if (tintColor == null) {

View File

@ -82,6 +82,7 @@ public class ReactImageView extends GenericDraweeView {
*/
private static final Matrix sMatrix = new Matrix();
private static final Matrix sInverse = new Matrix();
private ImageResizeMethod mResizeMethod = ImageResizeMethod.AUTO;
private class RoundedCornerPostprocessor extends BasePostprocessor {
@ -260,6 +261,11 @@ public class ReactImageView extends GenericDraweeView {
mIsDirty = true;
}
public void setResizeMethod(ImageResizeMethod resizeMethod) {
mResizeMethod = resizeMethod;
mIsDirty = true;
}
public void setSource(@Nullable ReadableArray sources) {
mSources.clear();
if (sources != null && sources.size() != 0) {
@ -451,12 +457,18 @@ public class ReactImageView extends GenericDraweeView {
mImageSource = mSources.get(0);
}
private static boolean shouldResize(ImageSource imageSource) {
private boolean shouldResize(ImageSource imageSource) {
// Resizing is inferior to scaling. See http://frescolib.org/docs/resizing-rotating.html#_
// We resize here only for images likely to be from the device's camera, where the app developer
// has no control over the original size
return
UriUtil.isLocalContentUri(imageSource.getUri()) ||
UriUtil.isLocalFileUri(imageSource.getUri());
if (mResizeMethod == ImageResizeMethod.AUTO) {
return
UriUtil.isLocalContentUri(imageSource.getUri()) ||
UriUtil.isLocalFileUri(imageSource.getUri());
} else if (mResizeMethod == ImageResizeMethod.RESIZE) {
return true;
} else {
return false;
}
}
}