Perform image decoding/optimization in the IO thread instead of main thread for better responsiveness (fix #18)
This new optimization is currently disabled by default so you can test it and give us feedback. To enable it, add #define ENABLE_SDWEBIMAGE_DECODER and to not forget to add SDWebImageDecoder class to your projet. Thanks to Adam Jernst (https://github.com/adamjernst) and James Tang (https://github.com/mystcolor) for this great optimization. See https://github.com/rs/SDWebImage/pull/18 for more info.
This commit is contained in:
parent
4792909c5b
commit
92d7a01a52
|
@ -7,8 +7,13 @@
|
|||
*/
|
||||
|
||||
#import "SDImageCache.h"
|
||||
#import "SDWebImageDecoder.h"
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
#ifdef ENABLE_SDWEBIMAGE_DECODER
|
||||
#import "SDWebImageDecoder.h"
|
||||
#endif
|
||||
|
||||
static NSInteger cacheMaxCacheAge = 60*60*24*7; // 1 week
|
||||
|
||||
static SDImageCache *instance;
|
||||
|
@ -173,6 +178,13 @@ static SDImageCache *instance;
|
|||
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:[self cachePathForKey:key]] autorelease];
|
||||
if (image)
|
||||
{
|
||||
#ifdef ENABLE_SDWEBIMAGE_DECODER
|
||||
UIImage *decodedImage = [UIImage decodedImageWithImage:image];
|
||||
if (decodedImage)
|
||||
{
|
||||
image = decodedImage;
|
||||
}
|
||||
#endif
|
||||
[mutableArguments setObject:image forKey:@"image"];
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* Created by james <https://github.com/mystcolor> on 9/28/11.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol SDWebImageDecoderDelegate;
|
||||
|
||||
@interface SDWebImageDecoder : NSObject
|
||||
{
|
||||
NSOperationQueue *imageDecodingQueue;
|
||||
}
|
||||
|
||||
+ (SDWebImageDecoder *)sharedImageDecoder;
|
||||
- (void)decodeImage:(UIImage *)image withDelegate:(id <SDWebImageDecoderDelegate>)delegate userInfo:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
@protocol SDWebImageDecoderDelegate <NSObject>
|
||||
|
||||
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIImage (ForceDecode)
|
||||
|
||||
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
|
||||
|
||||
@end
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* This file is part of the SDWebImage package.
|
||||
* (c) Olivier Poitrey <rs@dailymotion.com>
|
||||
*
|
||||
* Created by james <https://github.com/mystcolor> on 9/28/11.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
#import "SDWebImageDecoder.h"
|
||||
|
||||
#define DECOMPRESSED_IMAGE_KEY @"decompressedImage"
|
||||
#define DECODE_INFO_KEY @"decodeInfo"
|
||||
|
||||
#define IMAGE_KEY @"image"
|
||||
#define DELEGATE_KEY @"delegate"
|
||||
#define USER_INFO_KEY @"userInfo"
|
||||
|
||||
@implementation SDWebImageDecoder
|
||||
static SDWebImageDecoder *sharedInstance;
|
||||
|
||||
- (void)notifyDelegateOnMainThreadWithInfo:(NSDictionary *)dict
|
||||
{
|
||||
[dict retain];
|
||||
NSDictionary *decodeInfo = [dict objectForKey:DECODE_INFO_KEY];
|
||||
UIImage *decodedImage = [dict objectForKey:DECOMPRESSED_IMAGE_KEY];
|
||||
|
||||
id <SDWebImageDecoderDelegate> delegate = [decodeInfo objectForKey:DELEGATE_KEY];
|
||||
NSDictionary *userInfo = [decodeInfo objectForKey:USER_INFO_KEY];
|
||||
|
||||
[delegate imageDecoder:self didFinishDecodingImage:decodedImage userInfo:userInfo];
|
||||
[dict release];
|
||||
}
|
||||
|
||||
- (void)decodeImageWithInfo:(NSDictionary *)decodeInfo
|
||||
{
|
||||
UIImage *image = [decodeInfo objectForKey:IMAGE_KEY];
|
||||
|
||||
UIImage *decompressedImage = [UIImage decodedImageWithImage:image];
|
||||
if (!decompressedImage)
|
||||
{
|
||||
// If really have any error occurs, we use the original image at this moment
|
||||
decompressedImage = image;
|
||||
}
|
||||
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
decompressedImage, DECOMPRESSED_IMAGE_KEY,
|
||||
decodeInfo, DECODE_INFO_KEY, nil];
|
||||
|
||||
[self performSelectorOnMainThread:@selector(notifyDelegateOnMainThreadWithInfo:) withObject:dict waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
// Initialization code here.
|
||||
imageDecodingQueue = [[NSOperationQueue alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)decodeImage:(UIImage *)image withDelegate:(id<SDWebImageDecoderDelegate>)delegate userInfo:(NSDictionary *)info
|
||||
{
|
||||
NSDictionary *decodeInfo = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
image, IMAGE_KEY,
|
||||
delegate, DELEGATE_KEY,
|
||||
info, USER_INFO_KEY, nil];
|
||||
|
||||
NSOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(decodeImageWithInfo:) object:decodeInfo];
|
||||
[imageDecodingQueue addOperation:operation];
|
||||
[operation release];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[imageDecodingQueue release], imageDecodingQueue = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (SDWebImageDecoder *)sharedImageDecoder
|
||||
{
|
||||
if (!sharedInstance)
|
||||
{
|
||||
sharedInstance = [[SDWebImageDecoder alloc] init];
|
||||
}
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIImage (ForceDecode)
|
||||
|
||||
+ (UIImage *)decodedImageWithImage:(UIImage *)image
|
||||
{
|
||||
CGImageRef imageRef = image.CGImage;
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||
CGImageGetWidth(imageRef),
|
||||
CGImageGetHeight(imageRef),
|
||||
8,
|
||||
// Just always return width * 4 will be enough
|
||||
CGImageGetWidth(imageRef) * 4,
|
||||
// System only supports RGB, set explicitly
|
||||
colorSpace,
|
||||
// Makes system don't need to do extra conversion when displayed.
|
||||
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return nil;
|
||||
|
||||
CGRect rect = (CGRect){CGPointZero, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)};
|
||||
CGContextDrawImage(context, rect, imageRef);
|
||||
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
|
||||
UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef];
|
||||
CGImageRelease(decompressedImageRef);
|
||||
return [decompressedImage autorelease];
|
||||
}
|
||||
|
||||
@end
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
#import "SDWebImageDownloader.h"
|
||||
|
||||
#ifdef ENABLE_SDWEBIMAGE_DECODER
|
||||
#import "SDWebImageDecoder.h"
|
||||
@interface SDWebImageDownloader (ImageDecoder) <SDWebImageDecoderDelegate>
|
||||
@end
|
||||
#endif
|
||||
|
||||
NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification";
|
||||
NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification";
|
||||
|
||||
|
@ -120,7 +126,12 @@ NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNot
|
|||
if ([delegate respondsToSelector:@selector(imageDownloader:didFinishWithImage:)])
|
||||
{
|
||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||
|
||||
#ifdef ENABLE_SDWEBIMAGE_DECODER
|
||||
[[SDWebImageDecoder sharedImageDecoder] decodeImage:image withDelegate:self userInfo:nil];
|
||||
#else
|
||||
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
|
||||
#endif
|
||||
[image release];
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +149,15 @@ NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNot
|
|||
self.imageData = nil;
|
||||
}
|
||||
|
||||
#pragma mark SDWebImageDecoderDelegate
|
||||
|
||||
#ifdef ENABLE_SDWEBIMAGE_DECODER
|
||||
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo
|
||||
{
|
||||
[delegate performSelector:@selector(imageDownloader:didFinishWithImage:) withObject:self withObject:image];
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark NSObject
|
||||
|
||||
- (void)dealloc
|
||||
|
|
Loading…
Reference in New Issue