Skip to content

Commit 0b25f9a

Browse files
committed
Support using CoreGraphics to produce scaled down CGImage directly
1 parent e6cd1a9 commit 0b25f9a

File tree

1 file changed

+25
-20
lines changed

1 file changed

+25
-20
lines changed

SDWebImageWebPCoder/Classes/SDImageWebPCoder.m

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@
6868
#endif
6969
#endif
7070

71+
static inline CGImageRef __nullable CGBitmapContextCreateScaledImage(cg_nullable CGContextRef canvas, CGSize scaledSize) CF_RETURNS_RETAINED {
72+
if (!canvas) return NULL;
73+
CGContextSaveGState(canvas);
74+
CGContextScaleCTM(canvas, scaledSize.width, scaledSize.height);
75+
CGContextRestoreGState(canvas);
76+
return CGBitmapContextCreateImage(canvas);
77+
}
78+
7179
@interface SDWebPCoderFrame : NSObject
7280

7381
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based)
@@ -389,7 +397,14 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
389397

390398
// Only draw the last_y image height, keep remains transparent, in Core Graphics coordinate system
391399
CGContextDrawImage(canvas, CGRectMake(0, height - last_y, width, last_y), imageRef);
392-
CGImageRef newImageRef = CGBitmapContextCreateImage(canvas);
400+
// Check whether we need to use thumbnail
401+
CGImageRef newImageRef;
402+
CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:_thumbnailSize preserveAspectRatio:_preserveAspectRatio shouldScaleUp:NO];
403+
if (!CGSizeEqualToSize(CGSizeMake(width, height), scaledSize)) {
404+
newImageRef = CGBitmapContextCreateScaledImage(canvas, scaledSize);
405+
} else {
406+
newImageRef = CGBitmapContextCreateImage(canvas);
407+
}
393408
CGImageRelease(imageRef);
394409
if (!newImageRef) {
395410
CGContextRelease(canvas);
@@ -403,13 +418,6 @@ - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
403418
scale = 1;
404419
}
405420
}
406-
CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(width, height) scaleSize:_thumbnailSize preserveAspectRatio:_preserveAspectRatio shouldScaleUp:NO];
407-
// Check whether we need to use thumbnail
408-
if (!CGSizeEqualToSize(CGSizeMake(width, height), scaledSize)) {
409-
CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:newImageRef size:scaledSize];
410-
CGImageRelease(newImageRef);
411-
newImageRef = scaledImageRef;
412-
}
413421

414422
#if SD_UIKIT || SD_WATCH
415423
image = [[UIImage alloc] initWithCGImage:newImageRef scale:scale orientation:UIImageOrientationUp];
@@ -467,25 +475,22 @@ - (nullable CGImageRef)sd_drawnWebpImageWithCanvas:(CGContextRef)canvas iterator
467475
CGContextClearRect(canvas, imageRect);
468476
}
469477
CGContextDrawImage(canvas, imageRect, imageRef);
470-
CGImageRef newImageRef = CGBitmapContextCreateImage(canvas);
478+
479+
CGImageRef newImageRef;
480+
// Check whether we need to use thumbnail
481+
if (!CGSizeEqualToSize(CGSizeMake(canvasWidth, canvasHeight), scaledSize)) {
482+
// Use CoreGraphics canvas to scale down, no need extra allocation
483+
newImageRef = CGBitmapContextCreateScaledImage(canvas, scaledSize);
484+
} else {
485+
newImageRef = CGBitmapContextCreateImage(canvas);
486+
}
471487

472488
CGImageRelease(imageRef);
473489

474490
if (iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
475491
CGContextClearRect(canvas, imageRect);
476492
}
477493

478-
// Check whether we need to use thumbnail
479-
if (!CGSizeEqualToSize(CGSizeMake(canvasWidth, canvasHeight), scaledSize)) {
480-
// Important: For Animated WebP thumbnail generation, we can not just use a scaled small canvas and draw each thumbnail frame
481-
// 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
482-
// Because of this reason, even each frame contains small zigzag, the final animation contains visible glitch, this is not we want.
483-
// 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
484-
CGImageRef scaledImageRef = [SDImageCoderHelper CGImageCreateScaled:newImageRef size:scaledSize];
485-
CGImageRelease(newImageRef);
486-
newImageRef = scaledImageRef;
487-
}
488-
489494
return newImageRef;
490495
}
491496

0 commit comments

Comments
 (0)