Merge branch 'master' of https://github.com/rs/SDWebImage into 5.x

# Conflicts:
#	CHANGELOG.md
#	SDWebImage.podspec
#	SDWebImage/FLAnimatedImage/FLAnimatedImageView+WebCache.m
#	SDWebImage/SDImageCache.h
#	SDWebImage/SDWebImageCoderHelper.m
#	SDWebImage/SDWebImageCodersManager.m
#	SDWebImage/SDWebImageCompat.m
#	SDWebImage/SDWebImageGIFCoder.m
#	SDWebImage/SDWebImageImageIOCoder.m
#	SDWebImage/SDWebImageWebPCoder.m
#	SDWebImage/UIImage+MultiFormat.h
#	SDWebImage/UIImage+MultiFormat.m
#	SDWebImage/UIView+WebCache.h
#	SDWebImage/UIView+WebCache.m
#	WebImage/Info.plist
This commit is contained in:
DreamPiggy 2018-07-19 00:43:23 +08:00
commit d5b60c6b39
17 changed files with 144 additions and 82 deletions

View File

@ -1,3 +1,19 @@
## [4.4.2 - 4.4 patch, on July 18th, 2018](https://github.com/rs/SDWebImage/releases/tag/4.4.2)
See [all tickets marked for the 4.4.2 release](https://github.com/rs/SDWebImage/milestone/27)
#### Features
- Ability to change the clear cache option `SDImageCacheConfig.diskCacheExpireType` #2357
- Add option to enable or disable weak memory cache for `SDImageCache` via `SDImageCacheConfig.shouldUseWeakMemoryCache` #2379
- Add cache control for `FLAnimatedImage`, this allow user to disable memory cache for associated `FLAnimatedImage` instance #2378
- Add `diskImageDataForKey:` sync API for `SDImageCache` to directly get the image data from disk #2391
#### Fixes
- `SDWebImageManager.runningOperations` type changed from `Array` to `Set` #2382
- Keep the information about image's original compressed format #2390
- Fix `FLAnimatedImageView+WebCache` delayed draw due to #2047 which is now reverted #2393
- Check for nullable key when cancel image load operation #2386
- Replace `__bridge_transfer` with `__bridge` when convert from `CFStringRef` to `NSString` #2394
## [5.0.0-beta - Customizable SDWebImage, on Jul 17th, 2018](https://github.com/rs/SDWebImage/releases/tag/5.0.0-beta)
See [all tickets marked for the 5.0.0 release](https://github.com/rs/SDWebImage/milestone/15)

View File

@ -32,11 +32,19 @@ typedef NS_ENUM(NSInteger, SDImageFormat) {
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;
/**
Convert SDImageFormat to UTType
@param format Format as SDImageFormat
@return The UTType as CFStringRef
* Convert SDImageFormat to UTType
*
* @param format Format as SDImageFormat
* @return The UTType as CFStringRef
*/
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format CF_RETURNS_NOT_RETAINED;
/**
* Convert UTTyppe to SDImageFormat
*
* @param uttype The UTType as CFStringRef
* @return The Format as SDImageFormat
*/
+ (SDImageFormat)sd_imageFormatFromUTType:(nonnull CFStringRef)uttype;
@end

View File

@ -95,4 +95,27 @@
return UTType;
}
+ (SDImageFormat)sd_imageFormatFromUTType:(CFStringRef)uttype {
if (!uttype) {
return SDImageFormatUndefined;
}
SDImageFormat imageFormat;
if (CFStringCompare(uttype, kUTTypeJPEG, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatJPEG;
} else if (CFStringCompare(uttype, kUTTypePNG, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatPNG;
} else if (CFStringCompare(uttype, kUTTypeGIF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatGIF;
} else if (CFStringCompare(uttype, kUTTypeTIFF, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatTIFF;
} else if (CFStringCompare(uttype, kSDUTTypeWebP, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatWebP;
} else if (CFStringCompare(uttype, kSDUTTypeHEIC, 0) == kCFCompareEqualTo) {
imageFormat = SDImageFormatHEIC;
} else {
imageFormat = SDImageFormatUndefined;
}
return imageFormat;
}
@end

View File

@ -129,7 +129,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames];
animatedImage.sd_imageLoopCount = loopCount;
}
animatedImage.sd_imageFormat = SDImageFormatPNG;
CFRelease(source);
return animatedImage;
@ -309,6 +309,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(partialImageRef);
image.sd_imageFormat = SDImageFormatPNG;
}
}

View File

@ -200,6 +200,15 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
/**
* Asynchronously queries the cache with operation and call the completion when done.
* Query the image data for the given key synchronously.
*
* @param key The unique key used to store the wanted image
* @return The image data for the given key, or nil if not found.
*/
- (nullable NSData *)diskImageDataForKey:(nullable NSString *)key;
/**
* Operation that queries the cache asynchronously and call the completion when done.
*
* @param key The unique key used to store the wanted image
* @param doneBlock The completion block. Will not get called if the operation is cancelled
@ -235,6 +244,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
* Synchronously query the memory cache.
*
* @param key The unique key used to store the image
* @return The image for the given key, or nil if not found.
*/
- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key;
@ -242,6 +252,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
* Synchronously query the disk cache.
*
* @param key The unique key used to store the image
* @return The image for the given key, or nil if not found.
*/
- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key;
@ -249,6 +260,7 @@ typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) {
* Synchronously query the cache (memory and or disk) after checking the memory cache.
*
* @param key The unique key used to store the image
* @return The image for the given key, or nil if not found.
*/
- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key;

View File

@ -262,6 +262,18 @@
return [self.diskCache containsDataForKey:key];
}
- (nullable NSData *)diskImageDataForKey:(nullable NSString *)key {
if (!key) {
return nil;
}
__block NSData *imageData = nil;
dispatch_sync(self.ioQueue, ^{
imageData = [self diskImageDataBySearchingAllPathsForKey:key];
});
return imageData;
}
- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key {
return [self.memCache objectForKey:key];
}
@ -310,7 +322,7 @@
}
- (nullable UIImage *)diskImageForKey:(nullable NSString *)key {
NSData *data = [self diskImageDataBySearchingAllPathsForKey:key];
NSData *data = [self diskImageDataForKey:key];
return [self diskImageForKey:key data:data];
}

View File

@ -12,6 +12,7 @@
#import "NSData+ImageContentType.h"
#import "SDAnimatedImageRep.h"
#import "UIImage+ForceDecode.h"
#import "UIImage+Metadata.h"
#if SD_UIKIT || SD_WATCH
static const size_t kBytesPerPixel = 4;
@ -289,6 +290,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];
CGImageRelease(imageRef);
decodedImage.sd_isDecoded = YES;
decodedImage.sd_imageFormat = image.sd_imageFormat;
return decodedImage;
#endif
}
@ -422,6 +424,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return image;
}
destImage.sd_isDecoded = YES;
destImage.sd_imageFormat = image.sd_imageFormat;
return destImage;
}
#endif

View File

@ -122,7 +122,7 @@
animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames];
animatedImage.sd_imageLoopCount = loopCount;
}
animatedImage.sd_imageFormat = SDImageFormatGIF;
CFRelease(source);
return animatedImage;
@ -249,6 +249,7 @@
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
CGImageRelease(partialImageRef);
image.sd_imageFormat = SDImageFormatGIF;
}
}

View File

@ -10,7 +10,7 @@
#import "SDImageCoderHelper.h"
#import "NSImage+Compatibility.h"
#import <ImageIO/ImageIO.h>
#import "NSData+ImageContentType.h"
#import "UIImage+Metadata.h"
@implementation SDImageIOCoder {
size_t _width, _height;
@ -73,6 +73,7 @@
}
UIImage *image = [[UIImage alloc] initWithData:data scale:scale];
image.sd_imageFormat = [NSData sd_imageFormatForImageData:data];
return image;
}
@ -165,6 +166,8 @@
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation];
#endif
CGImageRelease(partialImageRef);
CFStringRef uttype = CGImageSourceGetType(_imageSource);
image.sd_imageFormat = [NSData sd_imageFormatFromUTType:uttype];
}
}

View File

@ -186,11 +186,6 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageOperationKey;
/**
A Dispatch group to maintain setImageBlock and completionBlock for view category. This is used for custom setImageBlock advanced usage, such like perform background task but need to guarantee the completion block is called after setImageBlock. (dispatch_group_t)
*/
FOUNDATION_EXPORT SDWebImageContextOption _Nonnull const SDWebImageContextSetImageGroup;
/**
A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager *)
*/

View File

@ -110,6 +110,7 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
#endif
}
scaledImage.sd_isIncremental = image.sd_isIncremental;
scaledImage.sd_imageFormat = image.sd_imageFormat;
return scaledImage;
}
@ -117,7 +118,6 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
#pragma mark - Context option
SDWebImageContextOption const SDWebImageContextSetImageOperationKey = @"setImageOperationKey";
SDWebImageContextOption const SDWebImageContextSetImageGroup = @"setImageGroup";
SDWebImageContextOption const SDWebImageContextCustomManager = @"customManager";
SDWebImageContextOption const SDWebImageContextImageTransformer = @"imageTransformer";
SDWebImageContextOption const SDWebImageContextImageScaleFactor = @"imageScaleFactor";

View File

@ -7,6 +7,7 @@
*/
#import "SDWebImageCompat.h"
#import "NSData+ImageContentType.h"
@interface UIImage (Metadata)
@ -21,6 +22,7 @@
* The setter of this property will set the loop count from GIF imageRep
*/
@property (nonatomic, assign) NSUInteger sd_imageLoopCount;
/**
* UIKit:
* Check the `images` array property
@ -29,6 +31,13 @@
*/
@property (nonatomic, assign, readonly) BOOL sd_isAnimated;
/**
* The image format represent the original compressed image data format.
* If you don't manually specify a format, this information is retrieve from CGImage using `CGImageGetUTType`, which may return nil for non-CG based image. At this time it will return `SDImageFormatUndefined` as default value.
* @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
*/
@property (nonatomic, assign) SDImageFormat sd_imageFormat;
/**
A bool value indicating whether the image is during incremental decoding and may not contains full pixels.
*/

View File

@ -10,10 +10,10 @@
#import "NSImage+Compatibility.h"
#import "objc/runtime.h"
#if SD_UIKIT || SD_WATCH
@implementation UIImage (Metadata)
#if SD_UIKIT || SD_WATCH
- (NSUInteger)sd_imageLoopCount {
NSUInteger imageLoopCount = 0;
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount));
@ -32,22 +32,7 @@
return (self.images != nil);
}
- (void)setSd_isIncremental:(BOOL)sd_isIncremental {
objc_setAssociatedObject(self, @selector(sd_isIncremental), @(sd_isIncremental), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)sd_isIncremental {
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_isIncremental));
return value.boolValue;
}
@end
#endif
#if SD_MAC
@implementation NSImage (Metadata)
#else
- (NSUInteger)sd_imageLoopCount {
NSUInteger imageLoopCount = 0;
@ -90,6 +75,27 @@
return isGIF;
}
#endif
- (SDImageFormat)sd_imageFormat {
SDImageFormat imageFormat = SDImageFormatUndefined;
NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageFormat));
if ([value isKindOfClass:[NSNumber class]]) {
imageFormat = value.integerValue;
return imageFormat;
}
// Check CGImage's UTType, may return nil for non-Image/IO based image
if (@available(iOS 9.0, tvOS 9.0, macOS 10.11, watchOS 2.0, *)) {
CFStringRef uttype = CGImageGetUTType(self.CGImage);
imageFormat = [NSData sd_imageFormatFromUTType:uttype];
}
return imageFormat;
}
- (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat {
objc_setAssociatedObject(self, @selector(sd_imageFormat), @(sd_imageFormat), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setSd_isIncremental:(BOOL)sd_isIncremental {
objc_setAssociatedObject(self, @selector(sd_isIncremental), @(sd_isIncremental), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@ -100,5 +106,3 @@
}
@end
#endif

View File

@ -27,8 +27,7 @@
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier]
autorelease];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
// Here we use the provided sd_setImageWithURL: method to load the web image

View File

@ -50,24 +50,10 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
} else {
validOperationKey = NSStringFromClass([self class]);
}
dispatch_group_t group = nil;
if ([context valueForKey:SDWebImageContextSetImageGroup]) {
group = [context valueForKey:SDWebImageContextSetImageGroup];
}
if (context && group) {
// Remove the context option for View Category only and pass others for manager
// Operation key may be useful for some advanced feature, keep it
SDWebImageMutableContext *mutableContext = [context mutableCopy];
[mutableContext removeObjectForKey:SDWebImageContextSetImageGroup];
context = [mutableContext copy];
}
[self sd_cancelImageLoadOperationWithKey:validOperationKey];
self.sd_imageURL = url;
if (!(options & SDWebImageDelayPlaceholder)) {
if (group) {
dispatch_group_enter(group);
}
dispatch_main_async_safe(^{
[self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock];
});
@ -165,30 +151,14 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
transition = sself.sd_imageTransition;
}
#endif
if (group) {
dispatch_group_enter(group);
dispatch_main_async_safe(^{
dispatch_main_async_safe(^{
#if SD_UIKIT || SD_MAC
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
#else
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
#endif
});
// ensure completion block is called after custom setImage process finish
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
callCompletedBlockClojure();
});
} else {
dispatch_main_async_safe(^{
#if SD_UIKIT || SD_MAC
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL];
#else
[sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock];
#endif
callCompletedBlockClojure();
});
}
callCompletedBlockClojure();
});
}];
[self sd_setImageLoadOperation:operation forKey:validOperationKey];
} else {

View File

@ -53,18 +53,21 @@ typedef NSMapTable<NSString *, id<SDWebImageOperation>> SDOperationsDictionary;
}
- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key {
// Cancel in progress downloader from queue
SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
id<SDWebImageOperation> operation;
@synchronized (self) {
operation = [operationDictionary objectForKey:key];
}
if (operation) {
if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]){
[operation cancel];
}
if (key) {
// Cancel in progress downloader from queue
SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
id<SDWebImageOperation> operation;
@synchronized (self) {
[operationDictionary removeObjectForKey:key];
operation = [operationDictionary objectForKey:key];
}
if (operation) {
if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) {
[operation cancel];
}
@synchronized (self) {
[operationDictionary removeObjectForKey:key];
}
}
}
}

View File

@ -153,6 +153,7 @@
#else
UIImage *firstFrameImage = [[UIImage alloc] initWithCGImage:imageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
firstFrameImage.sd_imageFormat = SDImageFormatWebP;
CGImageRelease(imageRef);
WebPDemuxReleaseIterator(&iter);
WebPDemuxDelete(demuxer);
@ -199,6 +200,7 @@
UIImage *animatedImage = [SDImageCoderHelper animatedImageWithFrames:frames];
animatedImage.sd_imageLoopCount = loopCount;
animatedImage.sd_imageFormat = SDImageFormatWebP;
return animatedImage;
}
@ -295,6 +297,7 @@
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
#endif
image.sd_isDecoded = YES; // Already drawn on bitmap context above
image.sd_imageFormat = SDImageFormatWebP;
CGImageRelease(newImageRef);
CGContextRelease(canvas);
}