From e71bbf239c9e827a70a6ee06fa55dd729062a8b9 Mon Sep 17 00:00:00 2001 From: DreamPiggy Date: Fri, 3 Apr 2020 23:28:08 +0800 Subject: [PATCH] Supports the encoding max pixel size options as well, which let the codec to do thumbnail rescale encoding, better performance than transformer to scale and then encode --- SDWebImage/Core/SDImageCoder.h | 9 ++++++- SDWebImage/Core/SDImageCoder.m | 1 + SDWebImage/Core/SDImageIOAnimatedCoder.m | 29 ++++++++++++++++++++- SDWebImage/Core/SDImageIOCoder.m | 32 ++++++++++++++++++++++-- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/SDWebImage/Core/SDImageCoder.h b/SDWebImage/Core/SDImageCoder.h index 3e0f3b72..5c03b2d4 100644 --- a/SDWebImage/Core/SDImageCoder.h +++ b/SDWebImage/Core/SDImageCoder.h @@ -57,10 +57,17 @@ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeCompressio /** A UIColor(NSColor) value to used for non-alpha image encoding when the input image has alpha channel, the background color will be used to compose the alpha one. If not provide, use white color. - @note works for `SDImageEncoder` + @note works for `SDImageCoder` */ FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeBackgroundColor; +/** + A CGSize value indicating the max image resolution in pixels during encoding. For vector image, this also effect the output vector data information about width and height. The encoder will not generate the encoded image larger than this limit. Note it always use the aspect ratio of input image. + Defaults to CGSizeZero, which means no max size limit at all. + @note works for `SDImageCoder` + */ +FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeMaxPixelSize; + /** A SDWebImageContext object which hold the original context options from top-level API. (SDWebImageContext) This option is ignored for all built-in coders and take no effect. diff --git a/SDWebImage/Core/SDImageCoder.m b/SDWebImage/Core/SDImageCoder.m index 14893ff2..58176547 100644 --- a/SDWebImage/Core/SDImageCoder.m +++ b/SDWebImage/Core/SDImageCoder.m @@ -16,5 +16,6 @@ SDImageCoderOption const SDImageCoderDecodeThumbnailPixelSize = @"decodeThumbnai SDImageCoderOption const SDImageCoderEncodeFirstFrameOnly = @"encodeFirstFrameOnly"; SDImageCoderOption const SDImageCoderEncodeCompressionQuality = @"encodeCompressionQuality"; SDImageCoderOption const SDImageCoderEncodeBackgroundColor = @"encodeBackgroundColor"; +SDImageCoderOption const SDImageCoderEncodeMaxPixelSize = @"encodeMaxPixelSize"; SDImageCoderOption const SDImageCoderWebImageContext = @"webImageContext"; diff --git a/SDWebImage/Core/SDImageIOAnimatedCoder.m b/SDWebImage/Core/SDImageIOAnimatedCoder.m index f5d518eb..253034ac 100644 --- a/SDWebImage/Core/SDImageIOAnimatedCoder.m +++ b/SDWebImage/Core/SDImageIOAnimatedCoder.m @@ -409,6 +409,11 @@ static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizati if (!image) { return nil; } + CGImageRef imageRef = image.CGImage; + if (!imageRef) { + // Earily return, supports CGImage only + return nil; + } if (format != self.class.imageFormat) { return nil; @@ -436,11 +441,33 @@ static NSString * kSDCGImageSourceRasterizationDPI = @"kCGImageSourceRasterizati if (backgroundColor) { properties[(__bridge NSString *)kCGImageDestinationBackgroundColor] = (__bridge id)(backgroundColor); } + CGSize maxPixelSize = CGSizeZero; + NSValue *maxPixelSizeValue = options[SDImageCoderEncodeMaxPixelSize]; + if (maxPixelSizeValue != nil) { +#if SD_MAC + maxPixelSize = maxPixelSizeValue.sizeValue; +#else + maxPixelSize = maxPixelSizeValue.CGSizeValue; +#endif + } + NSUInteger pixelWidth = CGImageGetWidth(imageRef); + NSUInteger pixelHeight = CGImageGetHeight(imageRef); + if (maxPixelSize.width > 0 && maxPixelSize.height > 0 && pixelWidth > 0 && pixelHeight > 0) { + CGFloat pixelRatio = pixelWidth / pixelHeight; + CGFloat maxPixelSizeRatio = maxPixelSize.width / maxPixelSize.height; + CGFloat finalPixelSize; + if (pixelRatio > maxPixelSizeRatio) { + finalPixelSize = maxPixelSize.width; + } else { + finalPixelSize = maxPixelSize.height; + } + properties[(__bridge NSString *)kCGImageDestinationImageMaxPixelSize] = @(finalPixelSize); + } BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // for static single images - CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); + CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); } else { // for animated images NSUInteger loopCount = image.sd_imageLoopCount; diff --git a/SDWebImage/Core/SDImageIOCoder.m b/SDWebImage/Core/SDImageIOCoder.m index 5ceefc4b..981d3593 100644 --- a/SDWebImage/Core/SDImageIOCoder.m +++ b/SDWebImage/Core/SDImageIOCoder.m @@ -221,9 +221,14 @@ if (!image) { return nil; } + CGImageRef imageRef = image.CGImage; + if (!imageRef) { + // Earily return, supports CGImage only + return nil; + } if (format == SDImageFormatUndefined) { - BOOL hasAlpha = [SDImageCoderHelper CGImageContainsAlpha:image.CGImage]; + BOOL hasAlpha = [SDImageCoderHelper CGImageContainsAlpha:imageRef]; if (hasAlpha) { format = SDImageFormatPNG; } else { @@ -258,9 +263,32 @@ if (backgroundColor) { properties[(__bridge NSString *)kCGImageDestinationBackgroundColor] = (__bridge id)(backgroundColor); } + CGSize maxPixelSize = CGSizeZero; + NSValue *maxPixelSizeValue = options[SDImageCoderEncodeMaxPixelSize]; + if (maxPixelSizeValue != nil) { +#if SD_MAC + maxPixelSize = maxPixelSizeValue.sizeValue; +#else + maxPixelSize = maxPixelSizeValue.CGSizeValue; +#endif + } + NSUInteger pixelWidth = CGImageGetWidth(imageRef); + NSUInteger pixelHeight = CGImageGetHeight(imageRef); + if (maxPixelSize.width > 0 && maxPixelSize.height > 0 && pixelWidth > 0 && pixelHeight > 0) { + CGFloat pixelRatio = pixelWidth / pixelHeight; + CGFloat maxPixelSizeRatio = maxPixelSize.width / maxPixelSize.height; + CGFloat finalPixelSize; + if (pixelRatio > maxPixelSizeRatio) { + finalPixelSize = maxPixelSize.width; + } else { + finalPixelSize = maxPixelSize.height; + } + properties[(__bridge NSString *)kCGImageDestinationImageMaxPixelSize] = @(finalPixelSize); + } + // Add your image to the destination. - CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); + CGImageDestinationAddImage(imageDestination, imageRef, (__bridge CFDictionaryRef)properties); // Finalize the destination. if (CGImageDestinationFinalize(imageDestination) == NO) {