From 1e632f107400058bc59bed8e7a9a2e23d2667bd6 Mon Sep 17 00:00:00 2001 From: Luke Dubert Date: Mon, 17 Aug 2015 13:36:22 -0400 Subject: [PATCH] add image size to onLoad nativeEvent add dimensions and scale properties to the nativeEvent add comments add check for images without intrinsic size only show size for network images clean up formatting create event first, check for nil change id dimensions to NSValue *dimensions change to NSValue *dimensions catch http images remove file git included add tests fix tests fix errors --- Examples/UIExplorer/ImageExample.js | 1 + .../UIExplorerUnitTests/RCTImageLoaderTests.m | 16 ++++++++-------- .../CameraRoll/RCTAssetsLibraryImageLoader.m | 6 +++--- Libraries/CameraRoll/RCTCameraRollManager.m | 2 +- .../CameraRoll/RCTPhotoLibraryImageLoader.m | 6 +++--- Libraries/Image/Image.ios.js | 3 ++- Libraries/Image/RCTGIFImageDecoder.m | 2 +- Libraries/Image/RCTImageEditingManager.m | 2 +- Libraries/Image/RCTImageLoader.h | 2 +- Libraries/Image/RCTImageLoader.m | 17 +++++++++-------- Libraries/Image/RCTImageStoreManager.m | 4 ++-- Libraries/Image/RCTImageView.m | 15 +++++++++++++-- Libraries/Image/RCTShadowVirtualImage.m | 2 +- Libraries/Image/RCTXCAssetImageLoader.m | 4 ++-- 14 files changed, 48 insertions(+), 34 deletions(-) diff --git a/Examples/UIExplorer/ImageExample.js b/Examples/UIExplorer/ImageExample.js index 4cab0c1a1cdab0..8a90c51a7f0eb9 100644 --- a/Examples/UIExplorer/ImageExample.js +++ b/Examples/UIExplorer/ImageExample.js @@ -73,6 +73,7 @@ exports.examples = [ console.log('woah', e.nativeEvent)} /> ); }, diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m index 04f367312a105a..3fc13e71112311 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m @@ -43,7 +43,7 @@ - (void)testImageLoading return YES; } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) { progressHandler(1, 1); - completionHandler(nil, image); + completionHandler(nil, image, nil); return nil; }]; @@ -53,7 +53,7 @@ - (void)testImageLoading [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:UIViewContentModeScaleAspectFit progressBlock:^(int64_t progress, int64_t total) { XCTAssertEqual(progress, 1); XCTAssertEqual(total, 1); - } completionBlock:^(NSError *loadError, id loadedImage) { + } completionBlock:^(NSError *loadError, id loadedImage, __unused NSValue *dimensions) { XCTAssertEqualObjects(loadedImage, image); XCTAssertNil(loadError); }]; @@ -67,7 +67,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority return YES; } loadImageURLHandler:^RCTImageLoaderCancellationBlock(__unused NSURL *imageURL, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderProgressBlock progressHandler, RCTImageLoaderCompletionBlock completionHandler) { progressHandler(1, 1); - completionHandler(nil, image); + completionHandler(nil, image, nil); return nil; }]; @@ -84,7 +84,7 @@ - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority [imageLoader loadImageWithTag:@"http://facebook.github.io/react/img/logo_og.png" size:CGSizeMake(100, 100) scale:1.0 resizeMode:UIViewContentModeScaleAspectFit progressBlock:^(int64_t progress, int64_t total) { XCTAssertEqual(progress, 1); XCTAssertEqual(total, 1); - } completionBlock:^(NSError *loadError, id loadedImage) { + } completionBlock:^(NSError *loadError, id loadedImage, __unused NSValue *dimensions) { XCTAssertEqualObjects(loadedImage, image); XCTAssertNil(loadError); }]; @@ -99,14 +99,14 @@ - (void)testImageDecoding return YES; } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) { XCTAssertEqualObjects(imageData, data); - completionHandler(nil, image); + completionHandler(nil, image, nil); return nil; }]; RCTImageLoader *imageLoader = [RCTImageLoader new]; NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder, imageLoader]; } launchOptions:nil]; - RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage) { + RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage, __unused NSValue *dimensions) { XCTAssertEqualObjects(decodedImage, image); XCTAssertNil(decodeError); }]; @@ -122,7 +122,7 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority return YES; } decodeImageDataHandler:^RCTImageLoaderCancellationBlock(NSData *imageData, __unused CGSize size, __unused CGFloat scale, __unused UIViewContentMode resizeMode, RCTImageLoaderCompletionBlock completionHandler) { XCTAssertEqualObjects(imageData, data); - completionHandler(nil, image); + completionHandler(nil, image, nil); return nil; }]; @@ -136,7 +136,7 @@ - (void)testImageLoaderUsesImageDecoderWithHighestPriority RCTImageLoader *imageLoader = [RCTImageLoader new]; NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[decoder1, decoder2, imageLoader]; } launchOptions:nil]; - RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage) { + RCTImageLoaderCancellationBlock cancelBlock = [imageLoader decodeImageData:data size:CGSizeMake(1, 1) scale:1.0 resizeMode:UIViewContentModeScaleToFill completionBlock:^(NSError *decodeError, id decodedImage, __unused NSValue *dimensions) { XCTAssertEqualObjects(decodedImage, image); XCTAssertNil(decodeError); }]; diff --git a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m index ebec0764ef2a60..8f11075bcc5862 100644 --- a/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m +++ b/Libraries/CameraRoll/RCTAssetsLibraryImageLoader.m @@ -109,12 +109,12 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL image = RCTScaledImageForAsset(representation, size, scale, resizeMode, &error); } - completionHandler(error, image); + completionHandler(error, image, nil); } }); } else { NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@ with no error message.", imageURL]; - completionHandler(RCTErrorWithMessage(errorText), nil); + completionHandler(RCTErrorWithMessage(errorText), nil, nil); } } failureBlock:^(NSError *loadError) { if (cancelled) { @@ -122,7 +122,7 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL } NSString *errorText = [NSString stringWithFormat:@"Failed to load asset at URL %@.\niOS Error: %@", imageURL, loadError]; - completionHandler(RCTErrorWithMessage(errorText), nil); + completionHandler(RCTErrorWithMessage(errorText), nil, nil); }]; return ^{ diff --git a/Libraries/CameraRoll/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m index ba36968568a50c..0b281b6088121f 100644 --- a/Libraries/CameraRoll/RCTCameraRollManager.m +++ b/Libraries/CameraRoll/RCTCameraRollManager.m @@ -30,7 +30,7 @@ @implementation RCTCameraRollManager successCallback:(RCTResponseSenderBlock)successCallback errorCallback:(RCTResponseErrorBlock)errorCallback) { - [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage) { + [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *loadError, UIImage *loadedImage, NSValue *dimensions) { if (loadError) { errorCallback(loadError); return; diff --git a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m index e4b2a217d67289..df3f1313e3deee 100644 --- a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m +++ b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m @@ -42,7 +42,7 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL PHFetchResult *results = [PHAsset fetchAssetsWithLocalIdentifiers:@[phAssetID] options:nil]; if (results.count == 0) { NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", phAssetID]; - completionHandler(RCTErrorWithMessage(errorText), nil); + completionHandler(RCTErrorWithMessage(errorText), nil, nil); return ^{}; } @@ -83,9 +83,9 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL options:imageOptions resultHandler:^(UIImage *result, NSDictionary *info) { if (result) { - completionHandler(nil, result); + completionHandler(nil, result, nil); } else { - completionHandler(info[PHImageErrorKey], nil); + completionHandler(info[PHImageErrorKey], nil, nil); } }]; diff --git a/Libraries/Image/Image.ios.js b/Libraries/Image/Image.ios.js index 4da2d53e50966a..606c93601f2145 100644 --- a/Libraries/Image/Image.ios.js +++ b/Libraries/Image/Image.ios.js @@ -127,7 +127,8 @@ var Image = React.createClass({ */ onError: PropTypes.func, /** - * Invoked when load completes successfully + * Invoked when load completes successfully. Network images + * will return with `{nativeEvent: {size}}`. * @platform ios */ onLoad: PropTypes.func, diff --git a/Libraries/Image/RCTGIFImageDecoder.m b/Libraries/Image/RCTGIFImageDecoder.m index 899a266e831fb3..d45f81b5dca4ac 100644 --- a/Libraries/Image/RCTGIFImageDecoder.m +++ b/Libraries/Image/RCTGIFImageDecoder.m @@ -104,7 +104,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData CFRelease(imageSource); } - completionHandler(nil, image); + completionHandler(nil, image, nil); return ^{}; } diff --git a/Libraries/Image/RCTImageEditingManager.m b/Libraries/Image/RCTImageEditingManager.m index cd81bbfbeed72f..2c2eb76808e618 100644 --- a/Libraries/Image/RCTImageEditingManager.m +++ b/Libraries/Image/RCTImageEditingManager.m @@ -51,7 +51,7 @@ @implementation RCTImageEditingManager return; } - [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *error, UIImage *image) { + [_bridge.imageLoader loadImageWithTag:imageTag callback:^(NSError *error, UIImage *image, NSValue *dimensions) { if (error) { errorCallback(error); return; diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index 770747452608b8..aef6321fed265a 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -15,7 +15,7 @@ @class ALAssetsLibrary; typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total); -typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image); +typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image, NSValue *dimensions); typedef void (^RCTImageLoaderCancellationBlock)(void); @interface UIImage (React) diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index 1f0b56d8848ab5..98a61e608e83c6 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -183,18 +183,18 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag } __block volatile uint32_t cancelled = 0; - RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *image) { + RCTImageLoaderCompletionBlock completionHandler = ^(NSError *error, UIImage *image, NSValue *dimensions) { if ([NSThread isMainThread]) { // Most loaders do not return on the main thread, so caller is probably not // expecting it, and may do expensive post-processing in the callback dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (!cancelled) { - completionBlock(error, image); + completionBlock(error, image, dimensions); } }); } else if (!cancelled) { - completionBlock(error, image); + completionBlock(error, image, dimensions); } }; @@ -232,7 +232,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag if (statusCode != 200) { completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain code:statusCode - userInfo:nil], nil); + userInfo:nil], nil, nil); return; } } @@ -264,7 +264,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithTag:(NSString *)imageTag RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock: ^(NSURLResponse *response, NSData *data, NSError *error) { if (error) { - completionHandler(error, nil); + completionHandler(error, nil, nil); return; } @@ -321,12 +321,13 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data return; } UIImage *image = [UIImage imageWithData:data scale:scale]; + NSValue *intrinsicSize = [NSValue valueWithCGSize:image.size]; if (image) { - completionHandler(nil, image); + completionHandler(nil, image, intrinsicSize); } else { NSString *errorMessage = [NSString stringWithFormat:@"Error decoding image data ", data, data.length]; NSError *finalError = RCTErrorWithMessage(errorMessage); - completionHandler(finalError, nil); + completionHandler(finalError, nil, nil); } }); @@ -353,7 +354,7 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request - (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate { __block RCTImageLoaderCancellationBlock requestToken; - requestToken = [self loadImageWithTag:request.URL.absoluteString callback:^(NSError *error, UIImage *image) { + requestToken = [self loadImageWithTag:request.URL.absoluteString callback:^(NSError *error, UIImage *image, NSValue *dimensions) { if (error) { [delegate URLRequest:requestToken didCompleteWithError:error]; return; diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m index 65a2e63f293073..3de376de1b56b2 100644 --- a/Libraries/Image/RCTImageStoreManager.m +++ b/Libraries/Image/RCTImageStoreManager.m @@ -109,11 +109,11 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL size:(CGSiz NSString *imageTag = imageURL.absoluteString; [self getImageForTag:imageTag withBlock:^(UIImage *image) { if (image) { - completionHandler(nil, image); + completionHandler(nil, image, nil); } else { NSString *errorMessage = [NSString stringWithFormat:@"Unable to load image from image store: %@", imageTag]; NSError *error = RCTErrorWithMessage(errorMessage); - completionHandler(error, nil); + completionHandler(error, nil, nil); } }]; diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index 4f4a65d331d1fb..311562dbaebb33 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -182,7 +182,7 @@ - (void)reloadImage scale:RCTScreenScale() resizeMode:self.contentMode progressBlock:progressHandler - completionBlock:^(NSError *error, UIImage *image) { + completionBlock:^(NSError *error, UIImage *image, NSValue *dimensions) { dispatch_async(dispatch_get_main_queue(), ^{ if (image.reactKeyframeAnimation) { [self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"]; @@ -196,7 +196,18 @@ - (void)reloadImage } } else { if (_onLoad) { - _onLoad(nil); + if (dimensions != nil) { + CGSize size = [dimensions CGSizeValue]; + _onLoad(@{ + @"size": @{ + @"height": @(size.height), + @"width": @(size.width), + } + }); + } + else { + _onLoad(nil); + } } } if (_onLoadEnd) { diff --git a/Libraries/Image/RCTShadowVirtualImage.m b/Libraries/Image/RCTShadowVirtualImage.m index 431fbac07afe9e..3494d5c7d55721 100644 --- a/Libraries/Image/RCTShadowVirtualImage.m +++ b/Libraries/Image/RCTShadowVirtualImage.m @@ -43,7 +43,7 @@ - (void)setSource:(NSDictionary *)source scale:scale resizeMode:UIViewContentModeScaleToFill progressBlock:nil - completionBlock:^(NSError *error, UIImage *image) { + completionBlock:^(NSError *error, UIImage *image, NSValue *dimensions) { dispatch_async(_bridge.uiManager.methodQueue, ^{ RCTShadowVirtualImage *strongSelf = weakSelf; diff --git a/Libraries/Image/RCTXCAssetImageLoader.m b/Libraries/Image/RCTXCAssetImageLoader.m index 799798a3662983..83a66f55312b64 100644 --- a/Libraries/Image/RCTXCAssetImageLoader.m +++ b/Libraries/Image/RCTXCAssetImageLoader.m @@ -41,10 +41,10 @@ - (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL if (progressHandler) { progressHandler(1, 1); } - completionHandler(nil, image); + completionHandler(nil, image, nil); } else { NSString *message = [NSString stringWithFormat:@"Could not find image named %@", imageName]; - completionHandler(RCTErrorWithMessage(message), nil); + completionHandler(RCTErrorWithMessage(message), nil, nil); } });