From 0b25f9ae03553f4f8e024c99442d7e4f260c7fb6 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Wed, 8 Mar 2023 14:37:20 +0800 Subject: [PATCH] Support using CoreGraphics to produce scaled down CGImage directly --- .../Classes/SDImageWebPCoder.m | 45 ++++++++++--------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m index d7be4c3..7b44810 100644 --- a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m +++ b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m @@ -68,6 +68,14 @@ else OSSpinLockUnlock(&lock##_deprecated); #endif #endif +static inline CGImageRef __nullable CGBitmapContextCreateScaledImage(cg_nullable CGContextRef canvas, CGSize scaledSize) CF_RETURNS_RETAINED { + if (!canvas) return NULL; + CGContextSaveGState(canvas); + CGContextScaleCTM(canvas, scaledSize.width, scaledSize.height); + CGContextRestoreGState(canvas); + return CGBitmapContextCreateImage(canvas); +} + @interface SDWebPCoderFrame : NSObject @property (nonatomic, assign) NSUInteger index; // Frame index (zero based) @@ -389,7 +397,14 @@ else OSSpinLockUnlock(&lock##_deprecated); // Only draw the last_y image height, keep remains transparent, in Core Graphics coordinate system CGContextDrawImage(canvas, CGRectMake(0, height - last_y, width, last_y), imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); + // Check whether we need to use thumbnail + CGImageRef newImageRef; + CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:_thumbnailSize preserveAspectRatio:_preserveAspectRatio shouldScaleUp:NO]; + if (!CGSizeEqualToSize(CGSizeMake(width, height), scaledSize)) { + newImageRef = CGBitmapContextCreateScaledImage(canvas, scaledSize); + } else { + newImageRef = CGBitmapContextCreateImage(canvas); + } CGImageRelease(imageRef); if (!newImageRef) { CGContextRelease(canvas); @@ -403,13 +418,6 @@ else OSSpinLockUnlock(&lock##_deprecated); scale = 1; } } - CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:_thumbnailSize preserveAspectRatio:_preserveAspectRatio shouldScaleUp:NO]; - // Check whether we need to use thumbnail - if (!CGSizeEqualToSize(CGSizeMake(width, height), scaledSize)) { - CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:newImageRef size:scaledSize]; - CGImageRelease(newImageRef); - newImageRef = scaledImageRef; - } #if SD_UIKIT || SD_WATCH image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp]; @@ -467,7 +475,15 @@ else OSSpinLockUnlock(&lock##_deprecated); CGContextClearRect(canvas, imageRect); } CGContextDrawImage(canvas, imageRect, imageRef); - CGImageRef newImageRef = CGBitmapContextCreateImage(canvas); + + CGImageRef newImageRef; + // Check whether we need to use thumbnail + if (!CGSizeEqualToSize(CGSizeMake(canvasWidth, canvasHeight), scaledSize)) { + // Use CoreGraphics canvas to scale down, no need extra allocation + newImageRef = CGBitmapContextCreateScaledImage(canvas, scaledSize); + } else { + newImageRef = CGBitmapContextCreateImage(canvas); + } CGImageRelease(imageRef); @@ -475,17 +491,6 @@ else OSSpinLockUnlock(&lock##_deprecated); CGContextClearRect(canvas, imageRect); } - // Check whether we need to use thumbnail - if (!CGSizeEqualToSize(CGSizeMake(canvasWidth, canvasHeight), scaledSize)) { - // Important: For Animated WebP thumbnail generation, we can not just use a scaled small canvas and draw each thumbnail frame - // This works **On Theory**. However, image scale down loss details. Animated WebP use the partial pixels with blend mode / dispose method with offset, to cover previous canvas status - // Because of this reason, even each frame contains small zigzag, the final animation contains visible glitch, this is not we want. - // So, always create the full pixels canvas (even though this consume more RAM), after drawn on the canvas, re-scale again with the final size - CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:newImageRef size:scaledSize]; - CGImageRelease(newImageRef); - newImageRef = scaledImageRef; - } - return newImageRef; }