Fix the issue for progressive decoding that do not parse the correct animated image scale. Update all coders
This commit is contained in:
parent
a22a0e25f7
commit
072b832375
|
@ -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) {
|
||||
|
|
|
@ -211,6 +211,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 +233,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 {
|
||||
|
@ -278,7 +283,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) {
|
||||
|
|
Loading…
Reference in New Issue