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 *)decodedAndScaledDownImageWithImage:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -50,7 +50,11 @@ typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) {
|
|||
*/
|
||||
SDWebImageDownloaderHighPriority = 1 << 7,
|
||||
|
||||
|
||||
/**
|
||||
* Scale down the image
|
||||
*/
|
||||
SDWebImageDownloaderScaleDownLargeImage = 1 << 8,
|
||||
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(^{
|
||||
|
|
Loading…
Reference in New Issue