diff --git a/Examples/UIExplorer/CameraRollExample.ios.js b/Examples/UIExplorer/CameraRollExample.ios.js index 73678407213224..9b745bd3b43ffa 100644 --- a/Examples/UIExplorer/CameraRollExample.ios.js +++ b/Examples/UIExplorer/CameraRollExample.ios.js @@ -70,7 +70,10 @@ var CameraRollExample = React.createClass({ return ( diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 7a629ce9a60c48..b372784cf0d29b 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -64,6 +64,11 @@ var Image = React.createClass({ */ source: PropTypes.shape({ uri: PropTypes.string, + /** + * Force display of the ALAsset in thumbnail format + * This property reduce the memory size and only works with ALAsset + */ + assetThumbnail: PropTypes.bool, }), /** * A static image to display while downloading the final image off the @@ -154,7 +159,11 @@ var Image = React.createClass({ tintColor: style.tintColor, }); if (isStored) { - nativeProps.imageTag = source.uri; + if (source.assetThumbnail && source.assetThumbnail === true){ + nativeProps.assetThumbnail = source.uri; + } else { + nativeProps.imageTag = source.uri; + } } else { nativeProps.src = source.uri; } @@ -178,6 +187,8 @@ var nativeOnlyProps = { src: true, defaultImageSrc: true, imageTag: true, + resizeMode: true, + assetThumbnail: true, }; if (__DEV__) { verifyPropTypes(Image, RCTStaticImage.viewConfig, nativeOnlyProps); diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js index c9b3dcac474200..8b58d6bc22b8b6 100644 --- a/Libraries/Image/ImageSource.js +++ b/Libraries/Image/ImageSource.js @@ -14,4 +14,5 @@ type ImageSource = { uri: string; isStatic: boolean; + assetThumbnail: boolean; }; diff --git a/Libraries/Image/RCTCameraRollManager.m b/Libraries/Image/RCTCameraRollManager.m index d7b42f88560aba..bcaa3ca6f07a6f 100644 --- a/Libraries/Image/RCTCameraRollManager.m +++ b/Libraries/Image/RCTCameraRollManager.m @@ -25,7 +25,7 @@ @implementation RCTCameraRollManager successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseSenderBlock)errorCallback) { - [RCTImageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) { + [RCTImageLoader loadImageWithTag:imageTag thumb:NO callback:^(NSError *loadError, UIImage *loadedImage) { if (loadError) { errorCallback(@[[loadError localizedDescription]]); return; diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index 186a53cd1046b0..b1857f28ddeece 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -21,6 +21,6 @@ * Will always call callback on main thread. */ + (void)loadImageWithTag:(NSString *)tag + thumb:(BOOL)thumb callback:(void (^)(NSError *error, id /* UIImage or CAAnimation */ image))callback; - @end diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index 04fa17f5d4b3d1..2267c3868418ee 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -60,7 +60,7 @@ + (ALAssetsLibrary *)assetsLibrary * Can be called from any thread. * Will always call callback on main thread. */ -+ (void)loadImageWithTag:(NSString *)imageTag callback:(void (^)(NSError *error, id image))callback ++ (void)loadImageWithTag:(NSString *)imageTag thumb:(BOOL)thumb callback:(void (^)(NSError *error, id image))callback { if ([imageTag hasPrefix:@"assets-library"]) { [[RCTImageLoader assetsLibrary] assetForURL:[NSURL URLWithString:imageTag] resultBlock:^(ALAsset *asset) { @@ -72,10 +72,17 @@ + (void)loadImageWithTag:(NSString *)imageTag callback:(void (^)(NSError *error, dispatch_async(RCTImageLoaderQueue(), ^{ // Also make sure the image is released immediately after it's used so it // doesn't spike the memory up during the process. + @autoreleasepool { + UIImage *image = nil; ALAssetRepresentation *representation = [asset defaultRepresentation]; ALAssetOrientation orientation = [representation orientation]; - UIImage *image = [UIImage imageWithCGImage:[representation fullResolutionImage] scale:1.0f orientation:(UIImageOrientation)orientation]; + if (!thumb) { + image = [UIImage imageWithCGImage:[representation fullResolutionImage] scale:1.0f orientation:(UIImageOrientation)orientation]; + } else { + image = [UIImage imageWithCGImage:[asset thumbnail]]; + } + RCTDispatchCallbackOnMainQueue(callback, nil, image); } }); diff --git a/Libraries/Image/RCTImageRequestHandler.m b/Libraries/Image/RCTImageRequestHandler.m index e5eb3bfd4f1d2c..6f881282b20d92 100644 --- a/Libraries/Image/RCTImageRequestHandler.m +++ b/Libraries/Image/RCTImageRequestHandler.m @@ -30,7 +30,7 @@ - (id)sendRequest:(NSURLRequest *)request { NSNumber *requestToken = @(++_currentToken); NSString *URLString = [request.URL absoluteString]; - [RCTImageLoader loadImageWithTag:URLString callback:^(NSError *error, UIImage *image) { + [RCTImageLoader loadImageWithTag:URLString thumb:NO callback:^(NSError *error, UIImage *image) { if (error) { [delegate URLRequest:requestToken didCompleteWithError:error]; return; diff --git a/Libraries/Image/RCTStaticImageManager.m b/Libraries/Image/RCTStaticImageManager.m index bdc6f0596a673d..70b5d0536a58d3 100644 --- a/Libraries/Image/RCTStaticImageManager.m +++ b/Libraries/Image/RCTStaticImageManager.m @@ -54,7 +54,7 @@ - (UIView *)view RCT_CUSTOM_VIEW_PROPERTY(imageTag, NSString, RCTStaticImage) { if (json) { - [RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, id image) { + [RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] thumb:NO callback:^(NSError *error, id image) { if (error) { RCTLogWarn(@"%@", error.localizedDescription); } @@ -70,5 +70,26 @@ - (UIView *)view view.image = defaultView.image; } } +RCT_CUSTOM_VIEW_PROPERTY(assetThumbnail, NSString, RCTStaticImage) +{ + if (json) { + [RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] thumb:YES callback:^(NSError *error, id image) { + if (error) { + RCTLogWarn(@"%@", error.localizedDescription); + } + if ([image isKindOfClass:[CAAnimation class]]) { + [view.layer addAnimation:image forKey:@"contents"]; + } else { + [view.layer removeAnimationForKey:@"contents"]; + view.image = image; + } + }]; + } else { + [view.layer removeAnimationForKey:@"contents"]; + view.image = defaultView.image; + } +} + + @end