Add option to scale down large images on iOS

Option is SDWebImageScaleDownLargeImage
This commit is contained in:
gsempe 2014-06-18 20:02:30 +02:00
parent f6fdaeb6ae
commit f0732d704c
6 changed files with 75 additions and 13 deletions

View File

@ -15,4 +15,6 @@
+ (UIImage *)decodedImageWithImage:(UIImage *)image;
+ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image;
@end

View File

@ -10,9 +10,30 @@
#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)
+ (UIImage *)decodedImageWithImage:(UIImage *)image {
+ (UIImage *)decodedAndScaledDownImageToSize:(CGSize)size withImage:(UIImage *)image {
if (image.images) {
// Do not decode animated images
return image;
@ -20,15 +41,20 @@
CGImageRef imageRef = image.CGImage;
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();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone ||
infoMask == kCGImageAlphaNoneSkipFirst ||
infoMask == kCGImageAlphaNoneSkipLast);
infoMask == kCGImageAlphaNoneSkipFirst ||
infoMask == kCGImageAlphaNoneSkipLast);
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
// https://developer.apple.com/library/mac/#qa/qa1037/_index.html
@ -39,7 +65,7 @@
// Set noneSkipFirst.
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) {
// Unset the old alpha info.
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
@ -48,17 +74,18 @@
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
CGContextRef context = CGBitmapContextCreate(NULL,
imageSize.width,
imageSize.height,
CGImageGetBitsPerComponent(imageRef),
0,
colorSpace,
bitmapInfo);
imageSize.width,
imageSize.height,
CGImageGetBitsPerComponent(imageRef),
0,
colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);
// If failed, return undecompressed image
if (!context) return image;
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextDrawImage(context, imageRect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
@ -69,4 +96,12 @@
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

View File

@ -50,7 +50,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
*/
SDWebImageDownloaderHighPriority = 1 << 7,
/**
* Scale down the image
*/
SDWebImageDownloaderScaleDownLargeImage = 1 << 8,
};
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {

View File

@ -357,7 +357,15 @@
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];
#endif
}
if (CGSizeEqualToSize(image.size, CGSizeZero)) {

View File

@ -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
* 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);

View File

@ -134,12 +134,17 @@
if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies;
if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates;
if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority;
if (options & SDWebImageScaleDownLargeImage) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImage;
if (image && options & SDWebImageRefreshCached) {
// force progressive off if image already cached but forced refreshing
downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
// ignore image read from NSURLCache if image if cached but force refreshing
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) {
if (weakOperation.isCancelled) {
dispatch_main_sync_safe(^{