Support using CoreGraphics to produce scaled down CGImage directly

This commit is contained in:
DreamPiggy 2023-03-08 14:37:20 +08:00
parent e6cd1a9d2c
commit 0b25f9ae03
1 changed files with 25 additions and 20 deletions

View File

@ -68,6 +68,14 @@ else OSSpinLockUnlock(&lock##_deprecated);
#endif #endif
#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 @interface SDWebPCoderFrame : NSObject
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) @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 // 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); 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); CGImageRelease(imageRef);
if (!newImageRef) { if (!newImageRef) {
CGContextRelease(canvas); CGContextRelease(canvas);
@ -403,13 +418,6 @@ else OSSpinLockUnlock(&lock##_deprecated);
scale = 1; 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 #if SD_UIKIT || SD_WATCH
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp]; image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp];
@ -467,7 +475,15 @@ else OSSpinLockUnlock(&lock##_deprecated);
CGContextClearRect(canvas, imageRect); CGContextClearRect(canvas, imageRect);
} }
CGContextDrawImage(canvas, imageRect, imageRef); 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); CGImageRelease(imageRef);
@ -475,17 +491,6 @@ else OSSpinLockUnlock(&lock##_deprecated);
CGContextClearRect(canvas, imageRect); 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; return newImageRef;
} }