From 8187d1f0ec867d252c8e91ca2a8475a185c2bd03 Mon Sep 17 00:00:00 2001 From: Alex Akers Date: Thu, 3 Sep 2015 05:53:16 -0700 Subject: [PATCH] Update image loader plugins --- .../UIExplorerUnitTests/RCTImageLoaderTests.m | 6 +-- Libraries/Image/RCTGIFImageDecoder.m | 2 +- Libraries/Image/RCTImageDownloader.m | 38 ++++++++++++++++-- Libraries/Image/RCTImageLoader.m | 16 +++++++- Libraries/Image/RCTImageStoreManager.h | 2 +- Libraries/Image/RCTImageStoreManager.m | 40 ------------------- 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m index 256f0e5c5..d0323df7a 100644 --- a/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m +++ b/Examples/UIExplorer/UIExplorerUnitTests/RCTImageLoaderTests.m @@ -50,14 +50,13 @@ RCTDefineImageDecoder(RCTImageLoaderTestsDecoder2) RCTImageLoader *imageLoader = [RCTImageLoader new]; NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader, imageLoader]; } launchOptions:nil]; - RCTImageLoaderCancellationBlock cancelBlock = [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) { + [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) { XCTAssertEqualObjects(loadedImage, image); XCTAssertNil(loadError); }]; - XCTAssertNil(cancelBlock); } - (void)testImageLoaderUsesImageURLLoaderWithHighestPriority @@ -82,14 +81,13 @@ RCTDefineImageDecoder(RCTImageLoaderTestsDecoder2) RCTImageLoader *imageLoader = [RCTImageLoader new]; NS_VALID_UNTIL_END_OF_SCOPE RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:^{ return @[loader1, loader2, imageLoader]; } launchOptions:nil]; - RCTImageLoaderCancellationBlock cancelBlock = [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) { + [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) { XCTAssertEqualObjects(loadedImage, image); XCTAssertNil(loadError); }]; - XCTAssertNil(cancelBlock); } - (void)testImageDecoding diff --git a/Libraries/Image/RCTGIFImageDecoder.m b/Libraries/Image/RCTGIFImageDecoder.m index 0419ed728..3d85f94e7 100644 --- a/Libraries/Image/RCTGIFImageDecoder.m +++ b/Libraries/Image/RCTGIFImageDecoder.m @@ -24,7 +24,7 @@ RCT_EXPORT_MODULE() char header[7] = {}; [imageData getBytes:header length:6]; - return !strcmp(header, "GIF87a") == 0 || !strcmp(header, "GIF89a"); + return !strcmp(header, "GIF87a") || !strcmp(header, "GIF89a"); } - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData size:(CGSize)size scale:(CGFloat)scale resizeMode:(UIViewContentMode)resizeMode completionHandler:(RCTImageLoaderCompletionBlock)completionHandler diff --git a/Libraries/Image/RCTImageDownloader.m b/Libraries/Image/RCTImageDownloader.m index 82f777895..f110bd628 100644 --- a/Libraries/Image/RCTImageDownloader.m +++ b/Libraries/Image/RCTImageDownloader.m @@ -37,8 +37,10 @@ RCT_EXPORT_MODULE() - (BOOL)canLoadImageURL:(NSURL *)requestURL { // Have to exclude 'file://' from the main bundle, otherwise this would conflict with RCTAssetBundleImageLoader - return [requestURL.scheme.lowercaseString hasPrefix:@"http"] || - ([requestURL.scheme.lowercaseString hasPrefix:@"file"] && ![requestURL.path hasPrefix:[NSBundle mainBundle].resourcePath]); + return + [requestURL.scheme compare:@"http" options:NSCaseInsensitiveSearch range:NSMakeRange(0, 4)] == NSOrderedSame || + ([requestURL.scheme caseInsensitiveCompare:@"file"] == NSOrderedSame && ![requestURL.path hasPrefix:[NSBundle mainBundle].resourcePath]) || + [requestURL.scheme caseInsensitiveCompare:@"data"] == NSOrderedSame; } /** @@ -103,7 +105,7 @@ RCT_EXPORT_MODULE() progressHandler:(RCTImageLoaderProgressBlock)progressHandler completionHandler:(RCTImageLoaderCompletionBlock)completionHandler { - if ([imageURL.scheme isEqualToString:@"http"]) { + if ([imageURL.scheme.lowercaseString hasPrefix:@"http"]) { __block RCTImageLoaderCancellationBlock decodeCancel = nil; __weak RCTImageDownloader *weakSelf = self; @@ -122,9 +124,37 @@ RCT_EXPORT_MODULE() decodeCancel(); } }; + } else if ([imageURL.scheme caseInsensitiveCompare:@"data"] == NSOrderedSame) { + __block BOOL cancelled = NO; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (cancelled) { + return; + } + + // Normally -dataWithContentsOfURL: would be bad but this is a data URL. + NSData *data = [NSData dataWithContentsOfURL:imageURL]; + + UIImage *image = [UIImage imageWithData:data]; + if (image) { + if (progressHandler) { + progressHandler(1, 1); + } + if (completionHandler) { + completionHandler(nil, image); + } + } else { + if (completionHandler) { + NSString *message = [NSString stringWithFormat:@"Invalid image data for URL: %@", imageURL]; + completionHandler(RCTErrorWithMessage(message), nil); + } + } + }); + return ^{ + cancelled = YES; + }; } else if ([imageURL.scheme isEqualToString:@"file"]) { __block BOOL cancelled = NO; - dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (cancelled) { return; } diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index ba4ac7ea1..422a189d5 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -87,9 +87,21 @@ RCT_EXPORT_MODULE() RCTLogError(@"No suitable image URL loader found for %@", imageTag); } - return [loadHandler loadImageForURL:requestURL size:size scale:scale resizeMode:resizeMode progressHandler:progressBlock completionHandler:^(NSError *error, id image) { + return [loadHandler loadImageForURL:requestURL size:size scale:scale resizeMode:resizeMode progressHandler:^(int64_t progress, int64_t total) { + if (!progressBlock) { + return; + } + + if ([NSThread isMainThread]) { + progressBlock(progress, total); + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + progressBlock(progress, total); + }); + } + } completionHandler:^(NSError *error, id image) { RCTDispatchCallbackOnMainQueue(completionBlock, error, image); - }]; + }] ?: ^{}; } - (id)imageDecoderForRequest:(NSData *)imageData diff --git a/Libraries/Image/RCTImageStoreManager.h b/Libraries/Image/RCTImageStoreManager.h index 5f6a1cd64..9862d1bb2 100644 --- a/Libraries/Image/RCTImageStoreManager.h +++ b/Libraries/Image/RCTImageStoreManager.h @@ -6,7 +6,7 @@ #import "RCTImageLoader.h" #import "RCTURLRequestHandler.h" -@interface RCTImageStoreManager : NSObject +@interface RCTImageStoreManager : NSObject /** * Set and get cached images. These must be called from the main thread. diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m index c7f5a9fd8..65a2e63f2 100644 --- a/Libraries/Image/RCTImageStoreManager.m +++ b/Libraries/Image/RCTImageStoreManager.m @@ -97,46 +97,6 @@ RCT_EXPORT_METHOD(addImageFromBase64:(NSString *)base64String } } -#pragma mark - RCTURLRequestHandler - -- (BOOL)canHandleRequest:(NSURLRequest *)request -{ - return [request.URL.scheme.lowercaseString isEqualToString:@"rct-image-store"]; -} - -- (id)sendRequest:(NSURLRequest *)request - withDelegate:(id)delegate -{ - NSString *imageTag = request.URL.absoluteString; - [self getImageForTag:imageTag withBlock:^(UIImage *image) { - if (!image) { - NSError *error = RCTErrorWithMessage([NSString stringWithFormat:@"Invalid imageTag: %@", imageTag]); - [delegate URLRequest:request didCompleteWithError:error]; - return; - } - - NSString *mimeType = nil; - NSData *imageData = nil; - if (RCTImageHasAlpha(image.CGImage)) { - mimeType = @"image/png"; - imageData = UIImagePNGRepresentation(image); - } else { - mimeType = @"image/jpeg"; - imageData = UIImageJPEGRepresentation(image, 1.0); - } - - NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL - MIMEType:mimeType - expectedContentLength:imageData.length - textEncodingName:nil]; - - [delegate URLRequest:request didReceiveResponse:response]; - [delegate URLRequest:request didReceiveData:imageData]; - [delegate URLRequest:request didCompleteWithError:nil]; - }]; - return request; -} - #pragma mark - RCTImageLoader - (BOOL)canLoadImageURL:(NSURL *)requestURL