Skip to content

Commit

Permalink
fix(ios): improve image rendering performance in main thread
Browse files Browse the repository at this point in the history
  • Loading branch information
ruifanyuan committed Dec 28, 2023
1 parent 5440642 commit 0416d19
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 16 deletions.
78 changes: 73 additions & 5 deletions modules/ios/image/HippyDefaultImageProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,70 @@ - (void)setImageData:(NSData *)imageData {
}
}

- (dispatch_queue_t)prepareQueue{
return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}

- (void)prepareForDisplay:(void (^)(UIImage *_Nullable))completionHandler{
UIImage *theImage = [self image];
BOOL fallback = YES;

if(theImage){
__weak typeof(self) weakSelf = self;
if (@available(iOS 15.0, *)) {
CFStringRef ut = CGImageGetUTType(theImage.CGImage);
// prepareForDisplayWithCompletionHandler support jpeg and heif only
if(ut != nil && (kCFCompareEqualTo == CFStringCompare(ut, kUTTypeJPEG, 0) ||
kCFCompareEqualTo == CFStringCompare(ut, (__bridge CFStringRef)@"public.heif", 0))){
fallback = NO;

[theImage prepareForDisplayWithCompletionHandler:^(UIImage * _Nullable prepared) {
typeof(self) strongSelf = weakSelf;
if(strongSelf){
@synchronized(strongSelf){
if(prepared){
strongSelf->_image = prepared;
}
completionHandler(prepared);
}
}
}];
return;
}
}


dispatch_async([self prepareQueue], ^{
UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc]
initWithSize:theImage.size
format:[UIGraphicsImageRendererFormat preferredFormat]];
UIImage *prepared = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
[theImage drawAtPoint:CGPointZero];
}];

typeof(self) strongSelf = weakSelf;
if(strongSelf){
@synchronized(strongSelf){
if(prepared){
strongSelf->_image = prepared;
}
completionHandler(prepared);
}
}
});
return;
}


if(fallback){
completionHandler(nil);
}
}

- (UIImage *)image {
CGFloat scale = [UIScreen mainScreen].scale;
if (!_image) {
UIImage *tmp;
if (_data) {
CGFloat view_width = _imageViewSize.width;
CGFloat view_height = _imageViewSize.height;
Expand All @@ -82,7 +143,7 @@ - (UIImage *)image {
(NSString *)kCGImageSourceThumbnailMaxPixelSize: @(maxDimensionInPixels)
};
CGImageRef downsampleImageRef = CGImageSourceCreateThumbnailAtIndex(ref, 0, (__bridge CFDictionaryRef)downsampleOptions);
_image = [UIImage imageWithCGImage:downsampleImageRef scale:scale orientation:UIImageOrientationUp];
tmp = [UIImage imageWithCGImage:downsampleImageRef scale:scale orientation:UIImageOrientationUp];
CGImageRelease(downsampleImageRef);
}
CFRelease(properties);
Expand All @@ -91,13 +152,20 @@ - (UIImage *)image {
}
}
} else {
_image = [self imageAtFrame:0];
tmp = [self imageAtFrame:0];
}
if(!tmp){
tmp = [UIImage imageWithData:_data scale:scale];
}
@synchronized (self) {
if(_image == nil){
_image = tmp;
}
}
}
if (!_image) {
_image = [UIImage imageWithData:_data scale:scale];
@synchronized (self) {
return _image;
}
return _image;
}

- (UIImage *)imageAtFrame:(NSUInteger)index {
Expand Down
3 changes: 3 additions & 0 deletions modules/ios/image/HippyImageProviderProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
*/
- (UIImage *)image;

/** prepare the image for display */
- (void)prepareForDisplay:(void (^_Nullable)(UIImage *_Nullable))completionHandler;

// for animated Image
@optional

Expand Down
10 changes: 1 addition & 9 deletions modules/ios/image/NSData+DataType.m
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,7 @@ - (BOOL)datatype_isAPNG {
}

- (BOOL)datatype_isAnimatedImage {
do {
if ([self datatype_isGif]) {
return YES;
}
if ([self datatype_isAPNG]) {
return YES;
}
} while (0);
return NO;
return [self datatype_isGif] || [self datatype_isAPNG];
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,24 @@ - (void)loadImageSource:(NSString *)path forView:(HippyImageView *)view {
HippyAssert(imageProvider, @"Image Provider is required");
imageProvider.imageDataPath = standardizeAssetUrlString;
[imageProvider setImageData:data];
dispatch_async(dispatch_get_main_queue(), ^{

void (^reloadImageInMain)(void) = ^{
HippyImageView *strongView = weakView;
if (strongView) {
[strongView setImageProvider:imageProvider];
[strongView reloadImage];
}
});
};

if([imageProvider imageCount] <= 1){
// prepare the still image for display before setting it to the imageview
[imageProvider prepareForDisplay:^(UIImage * _Nullable _) {
// subsequent call to the image provider will return the prepared image
dispatch_async(dispatch_get_main_queue(), reloadImageInMain);
}];
}else{
dispatch_async(dispatch_get_main_queue(), reloadImageInMain);
}
}
});
}
Expand Down

0 comments on commit 0416d19

Please sign in to comment.