Add option to scale down large images on iOS
Option is SDWebImageScaleDownLargeImage
This commit is contained in:
parent
f6fdaeb6ae
commit
f0732d704c
|
@ -15,4 +15,6 @@
|
||||||
|
|
||||||
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
|
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
|
||||||
|
|
||||||
|
+ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -10,9 +10,30 @@
|
||||||
|
|
||||||
#import "SDWebImageDecoder.h"
|
#import "SDWebImageDecoder.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Size in MB, compatible with all iOS devices.
|
||||||
|
*/
|
||||||
|
#define kSDWebImageDecoderMaxImageSizeMB 4.f
|
||||||
|
|
||||||
|
#define SDWebImageDecoderMaxTotalPixels(bitsPerComponent) ((kSDWebImageDecoderMaxImageSizeMB*1024.*1024.*8.)/bitsPerComponent)
|
||||||
|
|
||||||
|
inline static CGSize SDWebImageDecoderConstrainedSize(UIImage *image) {
|
||||||
|
CGImageRef imageRef = image.CGImage;
|
||||||
|
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
|
||||||
|
size_t imageBitsPerComponent = CGImageGetBitsPerComponent(imageRef);
|
||||||
|
CGFloat imageTotalPixels = imageSize.width * imageSize.height;
|
||||||
|
if (imageTotalPixels < SDWebImageDecoderMaxTotalPixels(imageBitsPerComponent)) {
|
||||||
|
return CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
|
||||||
|
}
|
||||||
|
CGFloat ratio = SDWebImageDecoderMaxTotalPixels(imageBitsPerComponent) / imageTotalPixels;
|
||||||
|
CGFloat maxWidth = imageSize.width * ratio;
|
||||||
|
CGFloat maxHeight = imageSize.height *ratio;
|
||||||
|
return CGSizeMake(floorf(maxWidth), floorf(maxHeight));
|
||||||
|
}
|
||||||
|
|
||||||
@implementation UIImage (ForceDecode)
|
@implementation UIImage (ForceDecode)
|
||||||
|
|
||||||
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
|
+ (UIImage *)decodedAndScaledDownImageToSize:(CGSize)size withImage:(UIImage *)image {
|
||||||
if (image.images) {
|
if (image.images) {
|
||||||
// Do not decode animated images
|
// Do not decode animated images
|
||||||
return image;
|
return image;
|
||||||
|
@ -20,15 +41,20 @@
|
||||||
|
|
||||||
CGImageRef imageRef = image.CGImage;
|
CGImageRef imageRef = image.CGImage;
|
||||||
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
|
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
|
||||||
CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize};
|
|
||||||
|
if ((size.width < imageSize.width) && (size.height < imageSize.height)) {
|
||||||
|
imageSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize};
|
||||||
|
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
|
||||||
|
|
||||||
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
|
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
|
||||||
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
|
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
|
||||||
infoMask == kCGImageAlphaNoneSkipFirst ||
|
infoMask == kCGImageAlphaNoneSkipFirst ||
|
||||||
infoMask == kCGImageAlphaNoneSkipLast);
|
infoMask == kCGImageAlphaNoneSkipLast);
|
||||||
|
|
||||||
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
|
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
|
||||||
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
|
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
|
||||||
|
@ -39,7 +65,7 @@
|
||||||
// Set noneSkipFirst.
|
// Set noneSkipFirst.
|
||||||
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
|
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
|
||||||
}
|
}
|
||||||
// Some PNGs tell us they have alpha but only 3 components. Odd.
|
// Some PNGs tell us they have alpha but only 3 components. Odd.
|
||||||
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) {
|
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) {
|
||||||
// Unset the old alpha info.
|
// Unset the old alpha info.
|
||||||
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
|
||||||
|
@ -48,17 +74,18 @@
|
||||||
|
|
||||||
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
|
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
|
||||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||||
imageSize.width,
|
imageSize.width,
|
||||||
imageSize.height,
|
imageSize.height,
|
||||||
CGImageGetBitsPerComponent(imageRef),
|
CGImageGetBitsPerComponent(imageRef),
|
||||||
0,
|
0,
|
||||||
colorSpace,
|
colorSpace,
|
||||||
bitmapInfo);
|
bitmapInfo);
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
|
||||||
// If failed, return undecompressed image
|
// If failed, return undecompressed image
|
||||||
if (!context) return image;
|
if (!context) return image;
|
||||||
|
|
||||||
|
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
|
||||||
CGContextDrawImage(context, imageRect, imageRef);
|
CGContextDrawImage(context, imageRect, imageRef);
|
||||||
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
|
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
|
||||||
|
|
||||||
|
@ -69,4 +96,12 @@
|
||||||
return decompressedImage;
|
return decompressedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
|
||||||
|
return [UIImage decodedAndScaledDownImageToSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) withImage:image];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image {
|
||||||
|
return [UIImage decodedAndScaledDownImageToSize:SDWebImageDecoderConstrainedSize(image) withImage:image];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -50,7 +50,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
|
||||||
*/
|
*/
|
||||||
SDWebImageDownloaderHighPriority = 1 << 7,
|
SDWebImageDownloaderHighPriority = 1 << 7,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale down the image
|
||||||
|
*/
|
||||||
|
SDWebImageDownloaderScaleDownLargeImage = 1 << 8,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
|
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
|
||||||
|
|
|
@ -357,7 +357,15 @@
|
||||||
|
|
||||||
if (!image.images) // Do not force decod animated GIFs
|
if (!image.images) // Do not force decod animated GIFs
|
||||||
{
|
{
|
||||||
|
#ifdef TARGET_OS_IPHONE
|
||||||
|
if (self.options & SDWebImageDownloaderScaleDownLargeImage) {
|
||||||
|
image = [UIImage decodedAndScaledDownImageWithImage:image];
|
||||||
|
} else {
|
||||||
|
image = [UIImage decodedImageWithImage:image];
|
||||||
|
}
|
||||||
|
#else
|
||||||
image = [UIImage decodedImageWithImage:image];
|
image = [UIImage decodedImageWithImage:image];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CGSizeEqualToSize(image.size, CGSizeZero)) {
|
if (CGSizeEqualToSize(image.size, CGSizeZero)) {
|
||||||
|
|
|
@ -74,7 +74,15 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
|
||||||
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
|
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
|
||||||
* of the placeholder image until after the image has finished loading.
|
* of the placeholder image until after the image has finished loading.
|
||||||
*/
|
*/
|
||||||
SDWebImageDelayPlaceholder = 1 << 9
|
SDWebImageDelayPlaceholder = 1 << 9,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, images are decoded respecting their original size. On iOS, this flag will scale down the
|
||||||
|
* images to a size compatible with the constrained memory of devices.
|
||||||
|
* If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated.
|
||||||
|
*/
|
||||||
|
SDWebImageScaleDownLargeImage = 1 << 10
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType);
|
typedef void(^SDWebImageCompletedBlock)(UIImage *image, NSError *error, SDImageCacheType cacheType);
|
||||||
|
|
|
@ -134,12 +134,17 @@
|
||||||
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
|
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
|
||||||
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
|
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
|
||||||
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
|
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
|
||||||
|
if (options & SDWebImageScaleDownLargeImage) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImage;
|
||||||
if (image && options & SDWebImageRefreshCached) {
|
if (image && options & SDWebImageRefreshCached) {
|
||||||
// force progressive off if image already cached but forced refreshing
|
// force progressive off if image already cached but forced refreshing
|
||||||
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
|
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
|
||||||
// ignore image read from NSURLCache if image if cached but force refreshing
|
// ignore image read from NSURLCache if image if cached but force refreshing
|
||||||
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
|
downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
|
||||||
}
|
}
|
||||||
|
if (options & SDWebImageProgressiveDownload) {
|
||||||
|
// Progressive download deactivate scale down
|
||||||
|
downloaderOptions &= ~SDWebImageDownloaderScaleDownLargeImage;
|
||||||
|
}
|
||||||
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
|
id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished) {
|
||||||
if (weakOperation.isCancelled) {
|
if (weakOperation.isCancelled) {
|
||||||
dispatch_main_sync_safe(^{
|
dispatch_main_sync_safe(^{
|
||||||
|
|
Loading…
Reference in New Issue