Merge pull request #2453 from dreampiggy/improvement_animation_class_protocol
Add one initializer with extra arg for custom animated image class to use possible coder options, to make it extensible
This commit is contained in:
commit
6892f9e818
|
@ -16,9 +16,20 @@
|
||||||
@protocol SDAnimatedImage <SDAnimatedImageProvider>
|
@protocol SDAnimatedImage <SDAnimatedImageProvider>
|
||||||
|
|
||||||
@required
|
@required
|
||||||
|
/**
|
||||||
|
Initializes and returns the image object with the specified data, scale factor and possible animation decoding options.
|
||||||
|
@note We use this to create animated image instance for normal animation decoding.
|
||||||
|
|
||||||
|
@param data The data object containing the image data.
|
||||||
|
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
||||||
|
@param options A dictionary containing any animation decoding options.
|
||||||
|
@return An initialized object
|
||||||
|
*/
|
||||||
|
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale options:(nullable SDImageCoderOptions *)options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initializes the image with an animated coder. You can use the coder to decode the image frame later.
|
Initializes the image with an animated coder. You can use the coder to decode the image frame later.
|
||||||
@note Normally we use `initWithData:scale:` to create custom animated image class. However, for progressive image decoding, we will use this with animated coder which conforms to `SDProgressiveImageCoder` as well instead.
|
@note We use this with animated coder which conforms to `SDProgressiveImageCoder` for progressive animation decoding.
|
||||||
|
|
||||||
@param animatedCoder An animated coder which conform `SDAnimatedImageCoder` protocol
|
@param animatedCoder An animated coder which conform `SDAnimatedImageCoder` protocol
|
||||||
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
@param scale The scale factor to assume when interpreting the image data. Applying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the `size` property.
|
||||||
|
@ -27,6 +38,7 @@
|
||||||
- (nullable instancetype)initWithAnimatedCoder:(nonnull id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale;
|
- (nullable instancetype)initWithAnimatedCoder:(nonnull id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale;
|
||||||
|
|
||||||
@optional
|
@optional
|
||||||
|
// These methods are used for optional advanced feature, like image frame preloading.
|
||||||
/**
|
/**
|
||||||
Pre-load all animated image frame into memory. Then later frame image request can directly return the frame for index without decoding.
|
Pre-load all animated image frame into memory. Then later frame image request can directly return the frame for index without decoding.
|
||||||
This method may be called on background thread.
|
This method may be called on background thread.
|
||||||
|
@ -63,7 +75,6 @@
|
||||||
- (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path;
|
- (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path;
|
||||||
- (nullable instancetype)initWithData:(nonnull NSData *)data;
|
- (nullable instancetype)initWithData:(nonnull NSData *)data;
|
||||||
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
||||||
- (nullable instancetype)initWithAnimatedCoder:(nonnull id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Current animated image format.
|
Current animated image format.
|
||||||
|
|
|
@ -276,6 +276,10 @@ static NSArray *SDBundlePreferredScales() {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
|
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale {
|
||||||
|
return [self initWithData:data scale:scale options:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale options:(SDImageCoderOptions *)options {
|
||||||
if (!data || data.length == 0) {
|
if (!data || data.length == 0) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -284,7 +288,10 @@ static NSArray *SDBundlePreferredScales() {
|
||||||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders) {
|
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders) {
|
||||||
if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) {
|
if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) {
|
||||||
if ([coder canDecodeFromData:data]) {
|
if ([coder canDecodeFromData:data]) {
|
||||||
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDImageCoderDecodeScaleFactor : @(scale)}];
|
if (!options) {
|
||||||
|
options = @{SDImageCoderDecodeScaleFactor : @(scale)};
|
||||||
|
}
|
||||||
|
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:options];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
/**
|
/**
|
||||||
Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+Metadata.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop.
|
Whehter or not to enable incremental image load for animated image. This is for the animated image which `sd_isIncremental` is YES (See `UIImage+Metadata.h`). If enable, animated image rendering will stop at the last frame available currently, and continue when another `setImage:` trigger, where the new animated image's `animatedImageData` should be updated from the previous one. If the `sd_isIncremental` is NO. The incremental image load stop.
|
||||||
@note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior.
|
@note If you are confused about this description, open Chrome browser to view some large GIF images with low network speed to see the animation behavior.
|
||||||
@note The best practice to use incremental load is using `initWithAnimatedCoder:scale` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image.
|
@note The best practice to use incremental load is using `initWithAnimatedCoder:scale:` in `SDAnimatedImage` with animated coder which conform to `SDProgressiveImageCoder` as well. Then call incremental update and incremental decode method to produce the image.
|
||||||
Default is YES. Set to NO to only render the static poster for incremental animated image.
|
Default is YES. Set to NO to only render the static poster for incremental animated image.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BOOL shouldIncrementalLoad;
|
@property (nonatomic, assign) BOOL shouldIncrementalLoad;
|
||||||
|
|
|
@ -20,23 +20,24 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS
|
||||||
if (scale < 1) {
|
if (scale < 1) {
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
||||||
|
if (context) {
|
||||||
|
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
||||||
|
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
||||||
|
coderOptions = [mutableCoderOptions copy];
|
||||||
|
}
|
||||||
|
|
||||||
if (!decodeFirstFrame) {
|
if (!decodeFirstFrame) {
|
||||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||||
// check whether we should use `SDAnimatedImage`
|
// check whether we should use `SDAnimatedImage`
|
||||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale];
|
image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
|
||||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!image) {
|
if (!image) {
|
||||||
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
|
||||||
if (context) {
|
|
||||||
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
|
||||||
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
|
||||||
coderOptions = [mutableCoderOptions copy];
|
|
||||||
}
|
|
||||||
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
||||||
}
|
}
|
||||||
if (image) {
|
if (image) {
|
||||||
|
|
|
@ -51,7 +51,6 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext;
|
||||||
/**
|
/**
|
||||||
This is the image coder protocol to provide custom image decoding/encoding.
|
This is the image coder protocol to provide custom image decoding/encoding.
|
||||||
These methods are all required to implement.
|
These methods are all required to implement.
|
||||||
You do not need to specify image scale during decoding because we may scale image later.
|
|
||||||
@note Pay attention that these methods are not called from main queue.
|
@note Pay attention that these methods are not called from main queue.
|
||||||
*/
|
*/
|
||||||
@protocol SDImageCoder <NSObject>
|
@protocol SDImageCoder <NSObject>
|
||||||
|
@ -71,7 +70,7 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext;
|
||||||
@note This protocol may supports decode animated image frames. You can use `+[SDImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames.
|
@note This protocol may supports decode animated image frames. You can use `+[SDImageCoderHelper animatedImageWithFrames:]` to produce an animated image with frames.
|
||||||
|
|
||||||
@param data The image data to be decoded
|
@param data The image data to be decoded
|
||||||
@param options A dictionary containing any decoding options. Pass @{SDImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only.
|
@param options A dictionary containing any decoding options. Pass @{SDImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for image. Pass @{SDImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only.
|
||||||
@return The decoded image from data
|
@return The decoded image from data
|
||||||
*/
|
*/
|
||||||
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data
|
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data
|
||||||
|
|
|
@ -34,23 +34,24 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS
|
||||||
if (scale < 1) {
|
if (scale < 1) {
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
||||||
|
if (context) {
|
||||||
|
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
||||||
|
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
||||||
|
coderOptions = [mutableCoderOptions copy];
|
||||||
|
}
|
||||||
|
|
||||||
if (!decodeFirstFrame) {
|
if (!decodeFirstFrame) {
|
||||||
// check whether we should use `SDAnimatedImage`
|
// check whether we should use `SDAnimatedImage`
|
||||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale];
|
image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
|
||||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!image) {
|
if (!image) {
|
||||||
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
|
||||||
if (context) {
|
|
||||||
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
|
||||||
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
|
||||||
coderOptions = [mutableCoderOptions copy];
|
|
||||||
}
|
|
||||||
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
||||||
}
|
}
|
||||||
if (image) {
|
if (image) {
|
||||||
|
@ -95,13 +96,20 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im
|
||||||
if (scale < 1) {
|
if (scale < 1) {
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
||||||
|
if (context) {
|
||||||
|
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
||||||
|
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
||||||
|
coderOptions = [mutableCoderOptions copy];
|
||||||
|
}
|
||||||
|
|
||||||
id<SDProgressiveImageCoder> progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey);
|
id<SDProgressiveImageCoder> progressiveCoder = objc_getAssociatedObject(operation, SDImageLoaderProgressiveCoderKey);
|
||||||
if (!progressiveCoder) {
|
if (!progressiveCoder) {
|
||||||
// We need to create a new instance for progressive decoding to avoid conflicts
|
// We need to create a new instance for progressive decoding to avoid conflicts
|
||||||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) {
|
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) {
|
||||||
if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] &&
|
if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] &&
|
||||||
[((id<SDProgressiveImageCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
[((id<SDProgressiveImageCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
||||||
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDImageCoderDecodeScaleFactor : @(scale)}];
|
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:coderOptions];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,12 +129,6 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!image) {
|
if (!image) {
|
||||||
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
|
||||||
if (context) {
|
|
||||||
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
|
||||||
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
|
||||||
coderOptions = [mutableCoderOptions copy];
|
|
||||||
}
|
|
||||||
image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions];
|
image = [progressiveCoder incrementalDecodedImageWithOptions:coderOptions];
|
||||||
}
|
}
|
||||||
if (image) {
|
if (image) {
|
||||||
|
|
|
@ -208,7 +208,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageS
|
||||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextStoreCacheType;
|
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextStoreCacheType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:` to create the instance (or `initWithAnimatedCoder:scale` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`.
|
A Class object which the instance is a `UIImage/NSImage` subclass and adopt `SDAnimatedImage` protocol. We will call `initWithData:scale:options:` to create the instance (or `initWithAnimatedCoder:scale:` when using progressive download) . If the instance create failed, fallback to normal `UIImage/NSImage`.
|
||||||
This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class).
|
This can be used to improve animated images rendering performance (especially memory usage on big animated images) with `SDAnimatedImageView` (Class).
|
||||||
*/
|
*/
|
||||||
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass;
|
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextAnimatedImageClass;
|
||||||
|
|
|
@ -108,10 +108,6 @@ static id<SDImageLoader> _defaultImageLoader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image {
|
|
||||||
return SDScaledImageForKey(key, image);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock {
|
- (SDWebImageCombinedOperation *)loadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDImageLoaderProgressBlock)progressBlock completed:(SDInternalCompletionBlock)completedBlock {
|
||||||
return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock];
|
return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue