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>
|
||||
|
||||
@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.
|
||||
@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 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;
|
||||
|
||||
@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.
|
||||
This method may be called on background thread.
|
||||
|
@ -63,7 +75,6 @@
|
|||
- (nullable instancetype)initWithContentsOfFile:(nonnull NSString *)path;
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data;
|
||||
- (nullable instancetype)initWithData:(nonnull NSData *)data scale:(CGFloat)scale;
|
||||
- (nullable instancetype)initWithAnimatedCoder:(nonnull id<SDAnimatedImageCoder>)animatedCoder scale:(CGFloat)scale;
|
||||
|
||||
/**
|
||||
Current animated image format.
|
||||
|
|
|
@ -276,6 +276,10 @@ static NSArray *SDBundlePreferredScales() {
|
|||
}
|
||||
|
||||
- (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) {
|
||||
return nil;
|
||||
}
|
||||
|
@ -284,7 +288,10 @@ static NSArray *SDBundlePreferredScales() {
|
|||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders) {
|
||||
if ([coder conformsToProtocol:@protocol(SDAnimatedImageCoder)]) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
@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.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldIncrementalLoad;
|
||||
|
|
|
@ -20,23 +20,24 @@ UIImage * _Nullable SDImageCacheDecodeImageData(NSData * _Nonnull imageData, NSS
|
|||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
if (!decodeFirstFrame) {
|
||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||
// check whether we should use `SDAnimatedImage`
|
||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale];
|
||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
||||
if (context) {
|
||||
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
||||
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
||||
coderOptions = [mutableCoderOptions copy];
|
||||
}
|
||||
|
||||
if (!decodeFirstFrame) {
|
||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||
// check whether we should use `SDAnimatedImage`
|
||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
|
||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
||||
}
|
||||
if (image) {
|
||||
|
|
|
@ -51,7 +51,6 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderWebImageContext;
|
|||
/**
|
||||
This is the image coder protocol to provide custom image decoding/encoding.
|
||||
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.
|
||||
*/
|
||||
@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.
|
||||
|
||||
@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
|
||||
*/
|
||||
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data
|
||||
|
|
|
@ -34,23 +34,24 @@ UIImage * _Nullable SDImageLoaderDecodeImageData(NSData * _Nonnull imageData, NS
|
|||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
if (!decodeFirstFrame) {
|
||||
// check whether we should use `SDAnimatedImage`
|
||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale];
|
||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
SDImageCoderOptions *coderOptions = @{SDImageCoderDecodeFirstFrameOnly : @(decodeFirstFrame), SDImageCoderDecodeScaleFactor : @(scale)};
|
||||
if (context) {
|
||||
SDImageCoderMutableOptions *mutableCoderOptions = [coderOptions mutableCopy];
|
||||
[mutableCoderOptions setValue:context forKey:SDImageCoderWebImageContext];
|
||||
coderOptions = [mutableCoderOptions copy];
|
||||
}
|
||||
|
||||
if (!decodeFirstFrame) {
|
||||
// check whether we should use `SDAnimatedImage`
|
||||
Class animatedImageClass = context[SDWebImageContextAnimatedImageClass];
|
||||
if ([animatedImageClass isSubclassOfClass:[UIImage class]] && [animatedImageClass conformsToProtocol:@protocol(SDAnimatedImage)]) {
|
||||
image = [[animatedImageClass alloc] initWithData:imageData scale:scale options:coderOptions];
|
||||
if (options & SDWebImagePreloadAllFrames && [image respondsToSelector:@selector(preloadAllFrames)]) {
|
||||
[((id<SDAnimatedImage>)image) preloadAllFrames];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
image = [[SDImageCodersManager sharedManager] decodedImageWithData:imageData options:coderOptions];
|
||||
}
|
||||
if (image) {
|
||||
|
@ -95,13 +96,20 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im
|
|||
if (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);
|
||||
if (!progressiveCoder) {
|
||||
// We need to create a new instance for progressive decoding to avoid conflicts
|
||||
for (id<SDImageCoder>coder in [SDImageCodersManager sharedManager].coders.reverseObjectEnumerator) {
|
||||
if ([coder conformsToProtocol:@protocol(SDProgressiveImageCoder)] &&
|
||||
[((id<SDProgressiveImageCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
||||
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDImageCoderDecodeScaleFactor : @(scale)}];
|
||||
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:coderOptions];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -121,12 +129,6 @@ UIImage * _Nullable SDImageLoaderDecodeProgressiveImageData(NSData * _Nonnull im
|
|||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
if (image) {
|
||||
|
|
|
@ -208,7 +208,7 @@ FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextImageS
|
|||
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).
|
||||
*/
|
||||
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 {
|
||||
return [self loadImageWithURL:url options:options context:nil progress:progressBlock completed:completedBlock];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue