Merge pull request #3355 from dreampiggy/feature_support_uiimage_preparefordisplay

Support using iOS 15 UIImage new API imageByPreparingForDisplay for faster force decoding
This commit is contained in:
DreamPiggy 2022-06-20 17:17:10 +08:00 committed by GitHub
commit 8743cdd633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 53 additions and 26 deletions

View File

@ -330,6 +330,19 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return image; return image;
} }
#if SD_UIKIT
// See: https://developer.apple.com/documentation/uikit/uiimage/3750834-imagebypreparingfordisplay
// Need CGImage-based
if (@available(iOS 15, tvOS 15, *)) {
UIImage *decodedImage = [image imageByPreparingForDisplay];
if (decodedImage) {
SDImageCopyAssociatedObject(image, decodedImage);
decodedImage.sd_isDecoded = YES;
return decodedImage;
}
}
#endif
CGImageRef imageRef = image.CGImage; CGImageRef imageRef = image.CGImage;
if (!imageRef) { if (!imageRef) {
return image; return image;
@ -355,36 +368,54 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return image; return image;
} }
if (![self shouldScaleDownImage:image limitBytes:bytes]) {
return [self decodedImageWithImage:image];
}
CGFloat destTotalPixels; CGFloat destTotalPixels;
CGFloat tileTotalPixels; CGFloat tileTotalPixels;
if (bytes == 0) { if (bytes == 0) {
bytes = kDestImageLimitBytes; bytes = [self defaultScaleDownLimitBytes];
} }
bytes = MAX(bytes, kBytesPerPixel);
destTotalPixels = bytes / kBytesPerPixel; destTotalPixels = bytes / kBytesPerPixel;
tileTotalPixels = destTotalPixels / 3; tileTotalPixels = destTotalPixels / 3;
CGImageRef sourceImageRef = image.CGImage;
CGSize sourceResolution = CGSizeZero;
sourceResolution.width = CGImageGetWidth(sourceImageRef);
sourceResolution.height = CGImageGetHeight(sourceImageRef);
if (![self shouldScaleDownImagePixelSize:sourceResolution limitBytes:bytes]) {
return [self decodedImageWithImage:image];
}
CGFloat sourceTotalPixels = sourceResolution.width * sourceResolution.height;
// Determine the scale ratio to apply to the input image
// that results in an output image of the defined size.
// see kDestImageSizeMB, and how it relates to destTotalPixels.
CGFloat imageScale = sqrt(destTotalPixels / sourceTotalPixels);
CGSize destResolution = CGSizeZero;
destResolution.width = MAX(1, (int)(sourceResolution.width * imageScale));
destResolution.height = MAX(1, (int)(sourceResolution.height * imageScale));
#if SD_UIKIT
// See: https://developer.apple.com/documentation/uikit/uiimage/3750835-imagebypreparingthumbnailofsize
// Need CGImage-based
if (@available(iOS 15, tvOS 15, *)) {
// Calculate thumbnail point size
CGFloat scale = image.scale ?: 1;
CGSize thumbnailSize = CGSizeMake(destResolution.width / scale, destResolution.height / scale);
UIImage *decodedImage = [image imageByPreparingThumbnailOfSize:thumbnailSize];
if (decodedImage) {
SDImageCopyAssociatedObject(image, decodedImage);
decodedImage.sd_isDecoded = YES;
return decodedImage;
}
}
#endif
CGContextRef destContext = NULL; CGContextRef destContext = NULL;
// autorelease the bitmap context and all vars to help system to free memory when there are memory warning. // autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
// on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
@autoreleasepool { @autoreleasepool {
CGImageRef sourceImageRef = image.CGImage;
CGSize sourceResolution = CGSizeZero;
sourceResolution.width = CGImageGetWidth(sourceImageRef);
sourceResolution.height = CGImageGetHeight(sourceImageRef);
CGFloat sourceTotalPixels = sourceResolution.width * sourceResolution.height;
// Determine the scale ratio to apply to the input image
// that results in an output image of the defined size.
// see kDestImageSizeMB, and how it relates to destTotalPixels.
CGFloat imageScale = sqrt(destTotalPixels / sourceTotalPixels);
CGSize destResolution = CGSizeZero;
destResolution.width = MAX(1, (int)(sourceResolution.width * imageScale));
destResolution.height = MAX(1, (int)(sourceResolution.height * imageScale));
// device color space // device color space
CGColorSpaceRef colorspaceRef = [self colorSpaceGetDeviceRGB]; CGColorSpaceRef colorspaceRef = [self colorSpaceGetDeviceRGB];
BOOL hasAlpha = [self CGImageContainsAlpha:sourceImageRef]; BOOL hasAlpha = [self CGImageContainsAlpha:sourceImageRef];
@ -592,14 +623,10 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return YES; return YES;
} }
+ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image limitBytes:(NSUInteger)bytes { + (BOOL)shouldScaleDownImagePixelSize:(CGSize)sourceResolution limitBytes:(NSUInteger)bytes {
BOOL shouldScaleDown = YES; BOOL shouldScaleDown = YES;
CGImageRef sourceImageRef = image.CGImage; CGFloat sourceTotalPixels = sourceResolution.width * sourceResolution.height;
CGSize sourceResolution = CGSizeZero;
sourceResolution.width = CGImageGetWidth(sourceImageRef);
sourceResolution.height = CGImageGetHeight(sourceImageRef);
float sourceTotalPixels = sourceResolution.width * sourceResolution.height;
if (sourceTotalPixels <= 0) { if (sourceTotalPixels <= 0) {
return NO; return NO;
} }
@ -609,7 +636,7 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
} }
bytes = MAX(bytes, kBytesPerPixel); bytes = MAX(bytes, kBytesPerPixel);
destTotalPixels = bytes / kBytesPerPixel; destTotalPixels = bytes / kBytesPerPixel;
float imageScale = destTotalPixels / sourceTotalPixels; CGFloat imageScale = destTotalPixels / sourceTotalPixels;
if (imageScale < 1) { if (imageScale < 1) {
shouldScaleDown = YES; shouldScaleDown = YES;
} else { } else {