Merge branch 'fix_coder_implementation' into 5.x
This commit is contained in:
commit
830fb0d358
|
@ -33,9 +33,6 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
|||
|
||||
@implementation SDWebImageAPNGCoder {
|
||||
size_t _width, _height;
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImageOrientation _orientation;
|
||||
#endif
|
||||
CGImageSourceRef _imageSource;
|
||||
NSData *_imageData;
|
||||
CGFloat _scale;
|
||||
|
@ -246,7 +243,16 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
|||
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
||||
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatPNG];
|
||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType});
|
||||
CGFloat scale = 1;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
}
|
||||
_scale = scale;
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
|
@ -290,7 +296,7 @@ const CFStringRef kCGImagePropertyAPNGUnclampedDelayTime = (__bridge CFStringRef
|
|||
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL);
|
||||
|
||||
if (partialImageRef) {
|
||||
CGFloat scale = 1;
|
||||
CGFloat scale = _scale;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
|
|
|
@ -114,7 +114,7 @@ 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
|
||||
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.
|
||||
@param options A dictionary containing any progressive decoding options (instance-level). Pass @{SDWebImageCoderDecodeScaleFactor: @(1.0)} to specify scale factor for progressive animated image (each frames should use the same scale).
|
||||
@return A new instance to do incremental decoding for the specify image format
|
||||
*/
|
||||
- (nonnull instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options;
|
||||
|
@ -129,7 +129,7 @@ FOUNDATION_EXPORT SDWebImageCoderOption _Nonnull const SDWebImageCoderEncodeComp
|
|||
|
||||
/**
|
||||
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.
|
||||
@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, conform to `SDWebImageAnimatedCoder` protocol as well and use `animatedImageFrameAtIndex:` instead.
|
||||
|
||||
@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
|
||||
|
|
|
@ -337,7 +337,7 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
|
||||
if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) {
|
||||
// Get the image data
|
||||
__block NSData *imageData = [self.imageData copy];
|
||||
NSData *imageData = [self.imageData copy];
|
||||
// Get the total bytes downloaded
|
||||
const NSUInteger totalSize = imageData.length;
|
||||
// Get the finish status
|
||||
|
@ -345,7 +345,7 @@ didReceiveResponse:(NSURLResponse *)response
|
|||
|
||||
// progressive decode the image in coder queue
|
||||
dispatch_async(self.coderQueue, ^{
|
||||
UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(data, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
||||
UIImage *image = SDWebImageLoaderDecodeProgressiveImageData(imageData, self.request.URL, finished, self, [[self class] imageOptionsFromDownloaderOptions:self.options], self.context);
|
||||
if (image) {
|
||||
// We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding.
|
||||
|
||||
|
|
|
@ -183,7 +183,16 @@
|
|||
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceShouldCache : @(YES)});
|
||||
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF];
|
||||
_imageSource = CGImageSourceCreateIncremental((__bridge CFDictionaryRef)@{(__bridge_transfer NSString *)kCGImageSourceTypeIdentifierHint : (__bridge_transfer NSString *)imageUTType});
|
||||
CGFloat scale = 1;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
}
|
||||
_scale = scale;
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
|
@ -227,7 +236,7 @@
|
|||
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL);
|
||||
|
||||
if (partialImageRef) {
|
||||
CGFloat scale = 1;
|
||||
CGFloat scale = _scale;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
|
|
|
@ -14,13 +14,9 @@
|
|||
|
||||
@implementation SDWebImageImageIOCoder {
|
||||
size_t _width, _height;
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
UIImageOrientation _orientation;
|
||||
#else
|
||||
CGImagePropertyOrientation _orientation;
|
||||
#endif
|
||||
CGImageSourceRef _imageSource;
|
||||
NSUInteger _frameCount;
|
||||
CGFloat _scale;
|
||||
BOOL _finished;
|
||||
}
|
||||
|
||||
|
@ -37,9 +33,7 @@
|
|||
- (void)didReceiveMemoryWarning:(NSNotification *)notification
|
||||
{
|
||||
if (_imageSource) {
|
||||
for (size_t i = 0; i < _frameCount; i++) {
|
||||
CGImageSourceRemoveCacheAtIndex(_imageSource, i);
|
||||
}
|
||||
CGImageSourceRemoveCacheAtIndex(_imageSource, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,19 +60,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (BOOL)canIncrementalDecodeFromData:(NSData *)data {
|
||||
switch ([NSData sd_imageFormatForImageData:data]) {
|
||||
case SDImageFormatWebP:
|
||||
// Do not support WebP progressive decoding
|
||||
return NO;
|
||||
case SDImageFormatHEIC:
|
||||
// Check HEIC decoding compatibility
|
||||
return [[self class] canDecodeFromHEICFormat];
|
||||
default:
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)decodedImageWithData:(NSData *)data options:(nullable SDWebImageCoderOptions *)options {
|
||||
if (!data) {
|
||||
return nil;
|
||||
|
@ -96,10 +77,32 @@
|
|||
}
|
||||
|
||||
#pragma mark - Progressive Decode
|
||||
|
||||
- (BOOL)canIncrementalDecodeFromData:(NSData *)data {
|
||||
switch ([NSData sd_imageFormatForImageData:data]) {
|
||||
case SDImageFormatWebP:
|
||||
// Do not support WebP progressive decoding
|
||||
return NO;
|
||||
case SDImageFormatHEIC:
|
||||
// Check HEIC decoding compatibility
|
||||
return [[self class] canDecodeFromHEICFormat];
|
||||
default:
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)initIncrementalWithOptions:(nullable SDWebImageCoderOptions *)options {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_imageSource = CGImageSourceCreateIncremental(NULL);
|
||||
CGFloat scale = 1;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
}
|
||||
_scale = scale;
|
||||
#if SD_UIKIT
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
|
||||
#endif
|
||||
|
@ -118,7 +121,6 @@
|
|||
|
||||
// Update the data source, we must pass ALL the data, not just the new bytes
|
||||
CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished);
|
||||
_frameCount = CGImageSourceGetCount(_imageSource);
|
||||
|
||||
if (_width + _height == 0) {
|
||||
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL);
|
||||
|
@ -136,11 +138,7 @@
|
|||
// which means the image below born of initWithCGIImage will be
|
||||
// oriented incorrectly sometimes. (Unlike the image born of initWithData
|
||||
// in didCompleteWithError.) So save it here and pass it on later.
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:(CGImagePropertyOrientation)orientationValue];
|
||||
#else
|
||||
_orientation = (CGImagePropertyOrientation)orientationValue;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +170,7 @@
|
|||
#endif
|
||||
|
||||
if (partialImageRef) {
|
||||
CGFloat scale = 1;
|
||||
CGFloat scale = _scale;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
|
@ -180,7 +178,8 @@
|
|||
}
|
||||
}
|
||||
#if SD_UIKIT || SD_WATCH
|
||||
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation];
|
||||
UIImageOrientation imageOrientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:_orientation];
|
||||
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:imageOrientation];
|
||||
#else
|
||||
image = [[UIImage alloc] initWithCGImage:partialImageRef scale:scale orientation:_orientation];
|
||||
#endif
|
||||
|
|
|
@ -77,23 +77,6 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull
|
|||
NSCParameterAssert(imageURL);
|
||||
NSCParameterAssert(operation);
|
||||
|
||||
id<SDWebImageProgressiveCoder> progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey);
|
||||
if (!progressiveCoder) {
|
||||
// We need to create a new instance for progressive decoding to avoid conflicts
|
||||
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders) {
|
||||
if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] &&
|
||||
[((id<SDWebImageProgressiveCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
||||
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:nil];
|
||||
break;
|
||||
}
|
||||
}
|
||||
objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
// If we can't find any progressive coder, disable progressive download
|
||||
if (!progressiveCoder) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
UIImage *image;
|
||||
id<SDWebImageCacheKeyFilter> cacheKeyFilter = [context valueForKey:SDWebImageContextCacheKeyFilter];
|
||||
NSString *cacheKey;
|
||||
|
@ -108,6 +91,22 @@ UIImage * _Nullable SDWebImageLoaderDecodeProgressiveImageData(NSData * _Nonnull
|
|||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
id<SDWebImageProgressiveCoder> progressiveCoder = objc_getAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey);
|
||||
if (!progressiveCoder) {
|
||||
// We need to create a new instance for progressive decoding to avoid conflicts
|
||||
for (id<SDWebImageCoder>coder in [SDWebImageCodersManager sharedManager].coders.reverseObjectEnumerator) {
|
||||
if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] &&
|
||||
[((id<SDWebImageProgressiveCoder>)coder) canIncrementalDecodeFromData:imageData]) {
|
||||
progressiveCoder = [[[coder class] alloc] initIncrementalWithOptions:@{SDWebImageCoderDecodeScaleFactor : @(scale)}];
|
||||
break;
|
||||
}
|
||||
}
|
||||
objc_setAssociatedObject(operation, SDWebImageLoaderProgressiveCoderKey, progressiveCoder, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
// If we can't find any progressive coder, disable progressive download
|
||||
if (!progressiveCoder) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[progressiveCoder updateIncrementalData:imageData finished:finished];
|
||||
if (!decodeFirstFrame) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#import "SDWebImageCoderHelper.h"
|
||||
#import "NSImage+Compatibility.h"
|
||||
#import "UIImage+WebCache.h"
|
||||
#import "UIImage+ForceDecode.h"
|
||||
#if __has_include(<webp/decode.h>) && __has_include(<webp/encode.h>) && __has_include(<webp/demux.h>) && __has_include(<webp/mux.h>)
|
||||
#import <webp/decode.h>
|
||||
#import <webp/encode.h>
|
||||
|
@ -211,6 +212,14 @@ dispatch_semaphore_signal(self->_lock);
|
|||
if (self) {
|
||||
// Progressive images need transparent, so always use premultiplied RGBA
|
||||
_idec = WebPINewRGB(MODE_bgrA, NULL, 0, 0);
|
||||
CGFloat scale = 1;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
}
|
||||
_scale = scale;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
@ -225,10 +234,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)incrementalFinished {
|
||||
return _finished;
|
||||
// libwebp current does not support progressive decoding for animated image, so no need to scan and update the frame information
|
||||
}
|
||||
|
||||
- (UIImage *)incrementalDecodedImageWithOptions:(SDWebImageCoderOptions *)options {
|
||||
|
@ -254,7 +260,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
// It will not keep memory barrier safe on x86 architechure (macOS & iPhone simulator) but on ARM architecture (iPhone & iPad & tv & watch) it works great
|
||||
// If different threads use WebPIDecGetRGB to grab rgba bitmap, it will contain the previous decoded bitmap data
|
||||
// So this will cause our drawed image looks strange(above is the current part but below is the previous part)
|
||||
// We only grab the last_y height and draw the last_y heigh instead of total height image
|
||||
// We only grab the last_y height and draw the last_y height instead of total height image
|
||||
// Besides fix, this can enhance performance since we do not need to create extra bitmap
|
||||
CGImageRef imageRef = CGImageCreate(width, last_y, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
|
||||
|
||||
|
@ -278,7 +284,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
CGContextRelease(canvas);
|
||||
return nil;
|
||||
}
|
||||
CGFloat scale = 1;
|
||||
CGFloat scale = _scale;
|
||||
if ([options valueForKey:SDWebImageCoderDecodeScaleFactor]) {
|
||||
scale = [[options valueForKey:SDWebImageCoderDecodeScaleFactor] doubleValue];
|
||||
if (scale < 1) {
|
||||
|
@ -291,6 +297,7 @@ dispatch_semaphore_signal(self->_lock);
|
|||
#else
|
||||
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:kCGImagePropertyOrientationUp];
|
||||
#endif
|
||||
image.sd_isDecoded = YES; // Already drawn on bitmap context above
|
||||
CGImageRelease(newImageRef);
|
||||
CGContextRelease(canvas);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue