Merge branch 'refactor_coder_animation' into 5.x
This commit is contained in:
commit
fa59de5f76
|
@ -287,7 +287,7 @@ static NSArray *SDBundlePreferredScales() {
|
||||||
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders) {
|
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders) {
|
||||||
if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) {
|
if ([coder conformsToProtocol:@protocol(SDWebImageAnimatedCoder)]) {
|
||||||
if ([coder canDecodeFromData:data]) {
|
if ([coder canDecodeFromData:data]) {
|
||||||
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data];
|
animatedCoder = [[[coder class] alloc] initWithAnimatedImageData:data options:@{SDWebImageCoderDecodeScaleFactor : @(scale)}];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
#endif
|
#endif
|
||||||
CGImageSourceRef _imageSource;
|
CGImageSourceRef _imageSource;
|
||||||
NSData *_imageData;
|
NSData *_imageData;
|
||||||
|
CGFloat _scale;
|
||||||
NSUInteger _loopCount;
|
NSUInteger _loopCount;
|
||||||
NSUInteger _frameCount;
|
NSUInteger _frameCount;
|
||||||
NSArray<SDAPNGCoderFrame *> *_frames;
|
NSArray<SDAPNGCoderFrame *> *_frames;
|
||||||
|
@ -106,7 +107,8 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
size_t count = CGImageSourceGetCount(source);
|
size_t count = CGImageSourceGetCount(source);
|
||||||
UIImage *animatedImage;
|
UIImage *animatedImage;
|
||||||
|
|
||||||
if (count <= 1) {
|
BOOL decodeFirstFrame = [options[SDWebImageCoderDecodeFirstFrameOnly] boolValue];
|
||||||
|
if (decodeFirstFrame || count <= 1) {
|
||||||
animatedImage = [[UIImage alloc] initWithData:data scale:scale];
|
animatedImage = [[UIImage alloc] initWithData:data scale:scale];
|
||||||
} else {
|
} else {
|
||||||
NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray array];
|
NSMutableArray<SDWebImageFrame *> *frames = [NSMutableArray array];
|
||||||
|
@ -198,14 +200,23 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
// Handle failure.
|
// Handle failure.
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
if (frames.count == 0) {
|
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
|
||||||
|
double compressionQuality = 1;
|
||||||
|
if ([options valueForKey:SDWebImageCoderEncodeCompressionQuality]) {
|
||||||
|
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];
|
||||||
|
}
|
||||||
|
[properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality];
|
||||||
|
|
||||||
|
BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue];
|
||||||
|
if (encodeFirstFrame || frames.count == 0) {
|
||||||
// for static single PNG images
|
// for static single PNG images
|
||||||
CGImageDestinationAddImage(imageDestination, image.CGImage, nil);
|
CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties);
|
||||||
} else {
|
} else {
|
||||||
// for animated APNG images
|
// for animated APNG images
|
||||||
NSUInteger loopCount = image.sd_imageLoopCount;
|
NSUInteger loopCount = image.sd_imageLoopCount;
|
||||||
NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)}};
|
NSDictionary *pngProperties = @{(__bridge_transfer NSString *)kCGImagePropertyAPNGLoopCount : @(loopCount)};
|
||||||
CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)pngProperties);
|
[properties setValue:pngProperties forKey:(__bridge_transfer NSString *)kCGImagePropertyPNGDictionary];
|
||||||
|
CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)properties);
|
||||||
|
|
||||||
for (size_t i = 0; i < frames.count; i++) {
|
for (size_t i = 0; i < frames.count; i++) {
|
||||||
SDWebImageFrame *frame = frames[i];
|
SDWebImageFrame *frame = frames[i];
|
||||||
|
@ -232,7 +243,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG);
|
return ([NSData sd_imageFormatForImageData:data] == SDImageFormatPNG);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initIncremental {
|
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
||||||
|
@ -299,7 +310,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - SDWebImageAnimatedCoder
|
#pragma mark - SDWebImageAnimatedCoder
|
||||||
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data {
|
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -315,6 +326,14 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
CFRelease(imageSource);
|
CFRelease(imageSource);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
CGFloat scale = 1;
|
||||||
|
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||||
|
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||||
|
if (scale < 1) {
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_scale = scale;
|
||||||
_imageSource = imageSource;
|
_imageSource = imageSource;
|
||||||
_imageData = data;
|
_imageData = data;
|
||||||
#if SD_UIKIT
|
#if SD_UIKIT
|
||||||
|
@ -384,9 +403,9 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
}
|
}
|
||||||
#if SD_MAC
|
#if SD_MAC
|
||||||
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1];
|
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale];
|
||||||
#else
|
#else
|
||||||
UIImage *image = [UIImage imageWithCGImage:newImageRef];
|
UIImage *image = [UIImage imageWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp];
|
||||||
#endif
|
#endif
|
||||||
CGImageRelease(newImageRef);
|
CGImageRelease(newImageRef);
|
||||||
return image;
|
return image;
|
||||||
|
|
|
@ -13,19 +13,32 @@
|
||||||
typedef NSString * SDWebImageCoderOption NS_STRING_ENUM;
|
typedef NSString * SDWebImageCoderOption NS_STRING_ENUM;
|
||||||
typedef NSDictionary<SDWebImageCoderOption, id> SDWebImageCoderOptions;
|
typedef NSDictionary<SDWebImageCoderOption, id> SDWebImageCoderOptions;
|
||||||
|
|
||||||
|
#pragma mark - Coder Options
|
||||||
|
// These options are for image decoding
|
||||||
/**
|
/**
|
||||||
A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber)
|
A Boolean value indicating whether to decode the first frame only for animated image during decoding. (NSNumber). If not provide, decode animated image if need.
|
||||||
|
@note works for `SDWebImageCoder`.
|
||||||
*/
|
*/
|
||||||
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly;
|
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeFirstFrameOnly;
|
||||||
/**
|
/**
|
||||||
A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber)
|
A CGFloat value which is greater than or equal to 1.0. This value specify the image scale factor for decoding. If not provide, use 1.0. (NSNumber)
|
||||||
|
@note works for `SDWebImageCoder`, `SDWebImageProgressiveCoder`, `SDWebImageAnimatedCoder`.
|
||||||
*/
|
*/
|
||||||
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScaleFactor;
|
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderDecodeScaleFactor;
|
||||||
|
|
||||||
|
// These options are for image encoding
|
||||||
|
/**
|
||||||
|
A Boolean value indicating whether to encode the first frame only for animated image during encoding. (NSNumber). If not provide, encode animated image if need.
|
||||||
|
@note works for `SDWebImageCoder`.
|
||||||
|
*/
|
||||||
|
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeFirstFrameOnly;
|
||||||
/**
|
/**
|
||||||
A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber)
|
A double value between 0.0-1.0 indicating the encode compression quality to produce the image data. If not provide, use 1.0. (NSNumber)
|
||||||
|
@note works for `SDWebImageCoder`
|
||||||
*/
|
*/
|
||||||
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality;
|
FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeCompressionQuality;
|
||||||
|
|
||||||
|
#pragma mark - Coder
|
||||||
/**
|
/**
|
||||||
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.
|
||||||
|
@ -46,6 +59,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Decode the image data to image.
|
Decode the image data to image.
|
||||||
|
@note This protocol may supports decode animated image frames. You can use `+[SDWebImageCoderHelper 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 @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only.
|
@param options A dictionary containing any decoding options. Pass @{SDWebImageCoderDecodeFirstFrameOnly: @(YES)} to decode the first frame only.
|
||||||
|
@ -66,6 +80,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Encode the image to image data.
|
Encode the image to image data.
|
||||||
|
@note This protocol may supports encode animated image frames. You can use `+[SDWebImageCoderHelper framesFromAnimatedImage:]` to assemble an animated image with frames.
|
||||||
|
|
||||||
@param image The image to be encoded
|
@param image The image to be encoded
|
||||||
@param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible
|
@param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible
|
||||||
|
@ -78,7 +93,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark - Progressive Coder
|
||||||
/**
|
/**
|
||||||
This is the image coder protocol to provide custom progressive image decoding.
|
This is the image coder protocol to provide custom progressive image decoding.
|
||||||
These methods are all required to implement.
|
These methods are all required to implement.
|
||||||
|
@ -99,9 +114,10 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts
|
Because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts
|
||||||
This init method should not return nil
|
This init method should not return nil
|
||||||
|
|
||||||
|
@param options A dictionary containing any progressive decoding options (instance-level). Currentlly there is no options for this and always pass nil. Kept for extensibility.
|
||||||
@return A new instance to do incremental decoding for the specify image format
|
@return A new instance to do incremental decoding for the specify image format
|
||||||
*/
|
*/
|
||||||
- (nonnull instancetype)initIncremental;
|
- (nonnull instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Update the incremental decoding when new image data available
|
Update the incremental decoding when new image data available
|
||||||
|
@ -113,14 +129,16 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Incremental decode the current image data to image.
|
Incremental decode the current image data to image.
|
||||||
|
@note Due to the performance issue for progressive decoding and the integration for image view. This method may only return the first frame image even if the image data is animated image. If you want progressive animated image decoding, also conform to `SDWebImageAnimatedCoder` and use `animatedImageFrameAtIndex` instead.
|
||||||
|
|
||||||
@param options A dictionary containing any decoding options.
|
@param options A dictionary containing any progressive decoding options. Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive image
|
||||||
@return The decoded image from current data
|
@return The decoded image from current data
|
||||||
*/
|
*/
|
||||||
- (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDWebImageCoderOptions *)options;
|
- (nullable UIImage *)incrementalDecodedImageWithOptions:(nullable SDWebImageCoderOptions *)options;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark - Animated Image Provider
|
||||||
/**
|
/**
|
||||||
This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDWebImageAnimatedCoder`
|
This is the animated image protocol to provide the basic function for animated image rendering. It's adopted by `SDAnimatedImage` and `SDWebImageAnimatedCoder`
|
||||||
*/
|
*/
|
||||||
|
@ -167,6 +185,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
#pragma mark - Animated Coder
|
||||||
/**
|
/**
|
||||||
This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format.
|
This is the animated image coder protocol for custom animated image class like `SDAnimatedImage`. Through it inherit from `SDWebImageCoder`. We currentlly only use the method `canDecodeFromData:` to detect the proper coder for specify animated image format.
|
||||||
*/
|
*/
|
||||||
|
@ -176,11 +195,12 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
||||||
/**
|
/**
|
||||||
Because animated image coder should keep the original data, we will alloc a new instance with the same class for the specify animated image data
|
Because animated image coder should keep the original data, we will alloc a new instance with the same class for the specify animated image data
|
||||||
The init method should return nil if it can't decode the specify animated image data to produce any frame.
|
The init method should return nil if it can't decode the specify animated image data to produce any frame.
|
||||||
After the instance created, we may call methods in `SDAnimatedImage` to produce animated image frame.
|
After the instance created, we may call methods in `SDAnimatedImageProvider` to produce animated image frame.
|
||||||
|
|
||||||
@param data The animated image data to be decode
|
@param data The animated image data to be decode
|
||||||
|
@param options A dictionary containing any animated decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for animated image (each frames should use the same scale).
|
||||||
@return A new instance to do animated decoding for specify image data
|
@return A new instance to do animated decoding for specify image data
|
||||||
*/
|
*/
|
||||||
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data;
|
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,4 +10,6 @@
|
||||||
|
|
||||||
SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly";
|
SDWebImageCoderOption const SDWebImageCoderDecodeFirstFrameOnly = @"decodeFirstFrameOnly";
|
||||||
SDWebImageCoderOption const SDWebImageCoderDecodeScaleFactor = @"decodeScaleFactor";
|
SDWebImageCoderOption const SDWebImageCoderDecodeScaleFactor = @"decodeScaleFactor";
|
||||||
|
|
||||||
|
SDWebImageCoderOption const SDWebImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly";
|
||||||
SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality";
|
SDWebImageCoderOption const SDWebImageCoderEncodeCompressionQuality = @"encodeCompressionQuality";
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* file that was distributed with this source code.
|
* file that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <ImageIO/ImageIO.h>
|
||||||
#import "SDWebImageCompat.h"
|
#import "SDWebImageCompat.h"
|
||||||
#import "SDWebImageFrame.h"
|
#import "SDWebImageFrame.h"
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
@param exifOrientation EXIF orientation
|
@param exifOrientation EXIF orientation
|
||||||
@return iOS orientation
|
@return iOS orientation
|
||||||
*/
|
*/
|
||||||
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation NS_SWIFT_NAME(imageOrientation(from:));
|
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation NS_SWIFT_NAME(imageOrientation(from:));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Convert an iOS orientation to an EXIF image orientation.
|
Convert an iOS orientation to an EXIF image orientation.
|
||||||
|
@ -98,7 +98,7 @@
|
||||||
@param imageOrientation iOS orientation
|
@param imageOrientation iOS orientation
|
||||||
@return EXIF orientation
|
@return EXIF orientation
|
||||||
*/
|
*/
|
||||||
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation;
|
+ (CGImagePropertyOrientation)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#import "SDWebImageFrame.h"
|
#import "SDWebImageFrame.h"
|
||||||
#import "NSImage+Additions.h"
|
#import "NSImage+Additions.h"
|
||||||
#import "NSData+ImageContentType.h"
|
#import "NSData+ImageContentType.h"
|
||||||
#import <ImageIO/ImageIO.h>
|
|
||||||
#import "SDAnimatedImageRep.h"
|
#import "SDAnimatedImageRep.h"
|
||||||
|
#import "UIImage+ForceDecode.h"
|
||||||
|
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
static const size_t kBytesPerPixel = 4;
|
static const size_t kBytesPerPixel = 4;
|
||||||
|
@ -286,6 +286,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
||||||
}
|
}
|
||||||
UIImage *decodedImage = [[UIImage alloc] initWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
UIImage *decodedImage = [[UIImage alloc] initWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
|
decodedImage.sd_isDecoded = YES;
|
||||||
return decodedImage;
|
return decodedImage;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -414,6 +415,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
||||||
if (destImage == nil) {
|
if (destImage == nil) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
destImage.sd_isDecoded = YES;
|
||||||
return destImage;
|
return destImage;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -421,32 +423,31 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
||||||
|
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
// Convert an EXIF image orientation to an iOS one.
|
// Convert an EXIF image orientation to an iOS one.
|
||||||
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation {
|
+ (UIImageOrientation)imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation {
|
||||||
// CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
|
|
||||||
UIImageOrientation imageOrientation = UIImageOrientationUp;
|
UIImageOrientation imageOrientation = UIImageOrientationUp;
|
||||||
switch (exifOrientation) {
|
switch (exifOrientation) {
|
||||||
case 1:
|
case kCGImagePropertyOrientationUp:
|
||||||
imageOrientation = UIImageOrientationUp;
|
imageOrientation = UIImageOrientationUp;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case kCGImagePropertyOrientationDown:
|
||||||
imageOrientation = UIImageOrientationDown;
|
imageOrientation = UIImageOrientationDown;
|
||||||
break;
|
break;
|
||||||
case 8:
|
case kCGImagePropertyOrientationLeft:
|
||||||
imageOrientation = UIImageOrientationLeft;
|
imageOrientation = UIImageOrientationLeft;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case kCGImagePropertyOrientationRight:
|
||||||
imageOrientation = UIImageOrientationRight;
|
imageOrientation = UIImageOrientationRight;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case kCGImagePropertyOrientationUpMirrored:
|
||||||
imageOrientation = UIImageOrientationUpMirrored;
|
imageOrientation = UIImageOrientationUpMirrored;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case kCGImagePropertyOrientationDownMirrored:
|
||||||
imageOrientation = UIImageOrientationDownMirrored;
|
imageOrientation = UIImageOrientationDownMirrored;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case kCGImagePropertyOrientationLeftMirrored:
|
||||||
imageOrientation = UIImageOrientationLeftMirrored;
|
imageOrientation = UIImageOrientationLeftMirrored;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case kCGImagePropertyOrientationRightMirrored:
|
||||||
imageOrientation = UIImageOrientationRightMirrored;
|
imageOrientation = UIImageOrientationRightMirrored;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -456,33 +457,32 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert an iOS orientation to an EXIF image orientation.
|
// Convert an iOS orientation to an EXIF image orientation.
|
||||||
+ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation {
|
+ (CGImagePropertyOrientation)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation {
|
||||||
// CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility
|
CGImagePropertyOrientation exifOrientation = kCGImagePropertyOrientationUp;
|
||||||
NSInteger exifOrientation = 1;
|
|
||||||
switch (imageOrientation) {
|
switch (imageOrientation) {
|
||||||
case UIImageOrientationUp:
|
case UIImageOrientationUp:
|
||||||
exifOrientation = 1;
|
exifOrientation = kCGImagePropertyOrientationUp;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationDown:
|
case UIImageOrientationDown:
|
||||||
exifOrientation = 3;
|
exifOrientation = kCGImagePropertyOrientationDown;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationLeft:
|
case UIImageOrientationLeft:
|
||||||
exifOrientation = 8;
|
exifOrientation = kCGImagePropertyOrientationLeft;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationRight:
|
case UIImageOrientationRight:
|
||||||
exifOrientation = 6;
|
exifOrientation = kCGImagePropertyOrientationRight;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationUpMirrored:
|
case UIImageOrientationUpMirrored:
|
||||||
exifOrientation = 2;
|
exifOrientation = kCGImagePropertyOrientationUpMirrored;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationDownMirrored:
|
case UIImageOrientationDownMirrored:
|
||||||
exifOrientation = 4;
|
exifOrientation = kCGImagePropertyOrientationDownMirrored;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationLeftMirrored:
|
case UIImageOrientationLeftMirrored:
|
||||||
exifOrientation = 5;
|
exifOrientation = kCGImagePropertyOrientationLeftMirrored;
|
||||||
break;
|
break;
|
||||||
case UIImageOrientationRightMirrored:
|
case UIImageOrientationRightMirrored:
|
||||||
exifOrientation = 7;
|
exifOrientation = kCGImagePropertyOrientationRightMirrored;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -494,6 +494,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
|
||||||
#pragma mark - Helper Fuction
|
#pragma mark - Helper Fuction
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
|
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
|
||||||
|
// Avoid extra decode
|
||||||
|
if (image.sd_isDecoded) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
// Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
|
// Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
|
||||||
if (image == nil) {
|
if (image == nil) {
|
||||||
return NO;
|
return NO;
|
||||||
|
|
|
@ -352,7 +352,7 @@ didReceiveResponse:(NSURLResponse *)response
|
||||||
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders) {
|
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders) {
|
||||||
if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] &&
|
if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] &&
|
||||||
[((id<SDWebImageProgressiveCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
[((id<SDWebImageProgressiveCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
||||||
self.progressiveCoder = [[[coder class] alloc] initIncremental];
|
self.progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
size_t _width, _height;
|
size_t _width, _height;
|
||||||
CGImageSourceRef _imageSource;
|
CGImageSourceRef _imageSource;
|
||||||
NSData *_imageData;
|
NSData *_imageData;
|
||||||
|
CGFloat _scale;
|
||||||
NSUInteger _loopCount;
|
NSUInteger _loopCount;
|
||||||
NSUInteger _frameCount;
|
NSUInteger _frameCount;
|
||||||
NSArray<SDGIFCoderFrame *> *_frames;
|
NSArray<SDGIFCoderFrame *> *_frames;
|
||||||
|
@ -179,7 +180,7 @@
|
||||||
return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF);
|
return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initIncremental {
|
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
||||||
|
@ -275,7 +276,9 @@
|
||||||
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];
|
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];
|
||||||
}
|
}
|
||||||
[properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality];
|
[properties setValue:@(compressionQuality) forKey:(__bridge_transfer NSString *)kCGImageDestinationLossyCompressionQuality];
|
||||||
if (frames.count == 0) {
|
|
||||||
|
BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue];
|
||||||
|
if (encodeFirstFrame || frames.count == 0) {
|
||||||
// for static single GIF images
|
// for static single GIF images
|
||||||
CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties);
|
CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties);
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +308,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - SDWebImageAnimatedCoder
|
#pragma mark - SDWebImageAnimatedCoder
|
||||||
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data {
|
- (nullable instancetype)initWithAnimatedImageData:(nullable NSData *)data options:(nullable SDWebImageCoderOptions *)options {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -321,6 +324,14 @@
|
||||||
CFRelease(imageSource);
|
CFRelease(imageSource);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
CGFloat scale = 1;
|
||||||
|
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||||
|
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||||
|
if (scale < 1) {
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_scale = scale;
|
||||||
_imageSource = imageSource;
|
_imageSource = imageSource;
|
||||||
_imageData = data;
|
_imageData = data;
|
||||||
#if SD_UIKIT
|
#if SD_UIKIT
|
||||||
|
@ -384,9 +395,9 @@
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
}
|
}
|
||||||
#if SD_MAC
|
#if SD_MAC
|
||||||
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:1];
|
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale];
|
||||||
#else
|
#else
|
||||||
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef];
|
UIImage *image = [[UIImage alloc] initWithCGImage:newImageRef scale:_scale orientation:UIImageOrientationUp];
|
||||||
#endif
|
#endif
|
||||||
CGImageRelease(newImageRef);
|
CGImageRelease(newImageRef);
|
||||||
return image;
|
return image;
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Progressive Decode
|
#pragma mark - Progressive Decode
|
||||||
- (instancetype)initIncremental {
|
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
_imageSource = CGImageSourceCreateIncremental(NULL);
|
_imageSource = CGImageSourceCreateIncremental(NULL);
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
// oriented incorrectly sometimes. (Unlike the image born of initWithData
|
// oriented incorrectly sometimes. (Unlike the image born of initWithData
|
||||||
// in didCompleteWithError.) So save it here and pass it on later.
|
// in didCompleteWithError.) So save it here and pass it on later.
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue];
|
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +327,7 @@
|
||||||
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
|
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
|
||||||
if (val) {
|
if (val) {
|
||||||
CFNumberGetValue(val, kCFNumberNSIntegerType, &exifOrientation);
|
CFNumberGetValue(val, kCFNumberNSIntegerType, &exifOrientation);
|
||||||
result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:exifOrientation];
|
result = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)exifOrientation];
|
||||||
} // else - if it's not set it remains at up
|
} // else - if it's not set it remains at up
|
||||||
CFRelease((CFTypeRef) properties);
|
CFRelease((CFTypeRef) properties);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ dispatch_semaphore_signal(self->_lock);
|
||||||
WebPIDecoder *_idec;
|
WebPIDecoder *_idec;
|
||||||
WebPDemuxer *_demux;
|
WebPDemuxer *_demux;
|
||||||
NSData *_imageData;
|
NSData *_imageData;
|
||||||
|
CGFloat _scale;
|
||||||
NSUInteger _loopCount;
|
NSUInteger _loopCount;
|
||||||
NSUInteger _frameCount;
|
NSUInteger _frameCount;
|
||||||
NSArray<SDWebPCoderFrame *> *_frames;
|
NSArray<SDWebPCoderFrame *> *_frames;
|
||||||
|
@ -205,7 +206,7 @@ dispatch_semaphore_signal(self->_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Progressive Decode
|
#pragma mark - Progressive Decode
|
||||||
- (instancetype)initIncremental {
|
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
// Progressive images need transparent, so always use premultiplied RGBA
|
// Progressive images need transparent, so always use premultiplied RGBA
|
||||||
|
@ -421,7 +422,9 @@ dispatch_semaphore_signal(self->_lock);
|
||||||
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];
|
compressionQuality = [[options valueForKey:SDWebImageCoderEncodeCompressionQuality] doubleValue];
|
||||||
}
|
}
|
||||||
NSArray<SDWebImageFrame *> *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image];
|
NSArray<SDWebImageFrame *> *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image];
|
||||||
if (frames.count == 0) {
|
|
||||||
|
BOOL encodeFirstFrame = [options[SDWebImageCoderEncodeFirstFrameOnly] boolValue];
|
||||||
|
if (encodeFirstFrame || frames.count == 0) {
|
||||||
// for static single webp image
|
// for static single webp image
|
||||||
data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality];
|
data = [self sd_encodedWebpDataWithImage:image quality:compressionQuality];
|
||||||
} else {
|
} else {
|
||||||
|
@ -516,7 +519,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - SDWebImageAnimatedCoder
|
#pragma mark - SDWebImageAnimatedCoder
|
||||||
- (instancetype)initWithAnimatedImageData:(NSData *)data {
|
- (instancetype)initWithAnimatedImageData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -534,6 +537,14 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
WebPDemuxDelete(demuxer);
|
WebPDemuxDelete(demuxer);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
CGFloat scale = 1;
|
||||||
|
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||||
|
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||||
|
if (scale < 1) {
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_scale = scale;
|
||||||
_demux = demuxer;
|
_demux = demuxer;
|
||||||
_imageData = data;
|
_imageData = data;
|
||||||
_currentBlendIndex = NSNotFound;
|
_currentBlendIndex = NSNotFound;
|
||||||
|
@ -667,9 +678,9 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
image = [[UIImage alloc] initWithCGImage:imageRef];
|
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
|
||||||
#else
|
#else
|
||||||
image = [[UIImage alloc] initWithCGImage:imageRef scale:1];
|
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale];
|
||||||
#endif
|
#endif
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
} else {
|
} else {
|
||||||
|
@ -697,9 +708,9 @@ static void FreeImageData(void *info, const void *data, size_t size) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
#if SD_UIKIT || SD_WATCH
|
#if SD_UIKIT || SD_WATCH
|
||||||
image = [[UIImage alloc] initWithCGImage:imageRef];
|
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale orientation:UIImageOrientationUp];
|
||||||
#else
|
#else
|
||||||
image = [[UIImage alloc] initWithCGImage:imageRef scale:1];
|
image = [[UIImage alloc] initWithCGImage:imageRef scale:_scale];
|
||||||
#endif
|
#endif
|
||||||
CGImageRelease(imageRef);
|
CGImageRelease(imageRef);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
|
|
||||||
@interface UIImage (ForceDecode)
|
@interface UIImage (ForceDecode)
|
||||||
|
|
||||||
|
/**
|
||||||
|
A bool value indicating whether the image has already been decoded. This can help to avoid extra force decode.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL sd_isDecoded;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Decompress (force decode before rendering) the provided image
|
Decompress (force decode before rendering) the provided image
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,19 @@
|
||||||
|
|
||||||
#import "UIImage+ForceDecode.h"
|
#import "UIImage+ForceDecode.h"
|
||||||
#import "SDWebImageCoderHelper.h"
|
#import "SDWebImageCoderHelper.h"
|
||||||
|
#import "objc/runtime.h"
|
||||||
|
|
||||||
@implementation UIImage (ForceDecode)
|
@implementation UIImage (ForceDecode)
|
||||||
|
|
||||||
|
- (BOOL)sd_isDecoded {
|
||||||
|
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isDecoded));
|
||||||
|
return value.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setSd_isDecoded:(BOOL)sd_isDecoded {
|
||||||
|
objc_setAssociatedObject(self, @selector(sd_isDecoded), @(sd_isDecoded), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
+ (UIImage *)sd_decodedImageWithImage:(UIImage *)image {
|
+ (UIImage *)sd_decodedImageWithImage:(UIImage *)image {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
return nil;
|
return nil;
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
@property (nonatomic, assign, readonly) BOOL sd_isAnimated;
|
@property (nonatomic, assign, readonly) BOOL sd_isAnimated;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Indicating whether the image is during incremental decoding and may not contains full pixels.
|
A bool value indicating whether the image is during incremental decoding and may not contains full pixels.
|
||||||
*/
|
*/
|
||||||
@property (nonatomic, assign) BOOL sd_isIncremental;
|
@property (nonatomic, assign) BOOL sd_isIncremental;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
|
|
||||||
static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count
|
static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count
|
||||||
|
|
||||||
|
// Internal header
|
||||||
|
@interface SDAnimatedImageView ()
|
||||||
|
|
||||||
|
@property (nonatomic, assign) BOOL isProgressive;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface SDAnimatedImageTest : SDTestCase
|
@interface SDAnimatedImageTest : SDTestCase
|
||||||
|
|
||||||
@property (nonatomic, strong) UIWindow *window;
|
@property (nonatomic, strong) UIWindow *window;
|
||||||
|
@ -55,7 +62,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
|
||||||
|
|
||||||
- (void)test03AnimatedImageInitWithAnimatedCoder {
|
- (void)test03AnimatedImageInitWithAnimatedCoder {
|
||||||
NSData *validData = [self testGIFData];
|
NSData *validData = [self testGIFData];
|
||||||
SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData];
|
SDWebImageGIFCoder *coder = [[SDWebImageGIFCoder alloc] initWithAnimatedImageData:validData options:nil];
|
||||||
SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1];
|
SDAnimatedImage *image = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1];
|
||||||
expect(image).notTo.beNil();
|
expect(image).notTo.beNil();
|
||||||
// enough, other can be test with InitWithData
|
// enough, other can be test with InitWithData
|
||||||
|
@ -134,7 +141,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
|
||||||
|
|
||||||
- (void)test09AnimatedImageViewSetProgressiveAnimatedImage {
|
- (void)test09AnimatedImageViewSetProgressiveAnimatedImage {
|
||||||
NSData *gifData = [self testGIFData];
|
NSData *gifData = [self testGIFData];
|
||||||
SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncremental];
|
SDWebImageGIFCoder *progressiveCoder = [[SDWebImageGIFCoder alloc] initIncrementalWithOptions:nil];
|
||||||
// simulate progressive decode, pass partial data
|
// simulate progressive decode, pass partial data
|
||||||
NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)];
|
NSData *partialData = [gifData subdataWithRange:NSMakeRange(0, gifData.length - 1)];
|
||||||
[progressiveCoder updateIncrementalData:partialData finished:NO];
|
[progressiveCoder updateIncrementalData:partialData finished:NO];
|
||||||
|
@ -145,7 +152,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
|
||||||
SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init];
|
SDAnimatedImageView *imageView = [[SDAnimatedImageView alloc] init];
|
||||||
imageView.image = partialImage;
|
imageView.image = partialImage;
|
||||||
|
|
||||||
BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
BOOL isProgressive = imageView.isProgressive;
|
||||||
expect(isProgressive).equal(YES);
|
expect(isProgressive).equal(YES);
|
||||||
|
|
||||||
// pass full data
|
// pass full data
|
||||||
|
@ -155,7 +162,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
|
||||||
|
|
||||||
imageView.image = fullImage;
|
imageView.image = fullImage;
|
||||||
|
|
||||||
isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
isProgressive = imageView.isProgressive;
|
||||||
expect(isProgressive).equal(NO);
|
expect(isProgressive).equal(NO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +189,7 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun
|
||||||
// Progressive image may be nil when download data is not enough
|
// Progressive image may be nil when download data is not enough
|
||||||
if (image) {
|
if (image) {
|
||||||
expect(image.sd_isIncremental).beTruthy();
|
expect(image.sd_isIncremental).beTruthy();
|
||||||
BOOL isProgressive = [[imageView valueForKey:@"isProgressive"] boolValue];
|
BOOL isProgressive = imageView.isProgressive;
|
||||||
expect(isProgressive).equal(YES);
|
expect(isProgressive).equal(YES);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initIncremental
|
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self) {
|
if (self) {
|
||||||
|
|
Loading…
Reference in New Issue