Merge pull request #75 from SDWebImage/feat/limit_bytes

Added the support for 5.16.0+ limit bytes feature from SDWebImage Coder Plugin API
This commit is contained in:
DreamPiggy 2023-06-14 21:11:54 +08:00 committed by GitHub
commit f4c09076d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 78 additions and 28 deletions

View File

@ -74,27 +74,13 @@ jobs:
- name: Test - ${{ matrix.iosDestination }} - name: Test - ${{ matrix.iosDestination }}
run: | run: |
set -o pipefail set -o pipefail
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests iOS" -destination "${{ matrix.iosDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "SDWebImageWebPCoderTests" -destination "${{ matrix.iosDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/iOS
- name: Test - ${{ matrix.macOSDestination }}
run: |
set -o pipefail
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests Mac" -destination "${{ matrix.macOSDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/macOS
- name: Test - ${{ matrix.tvOSDestination }}
run: |
set -o pipefail
xcodebuild test -workspace "${{ env.WORKSPACE_NAME }}" -scheme "Tests TV" -destination "${{ matrix.tvOSDestination }}" -configuration Debug CODE_SIGNING_ALLOWED=NO
mv ~/Library/Developer/Xcode/DerivedData/ ./DerivedData/tvOS
- name: Code Coverage - name: Code Coverage
run: | run: |
set -o pipefail set -o pipefail
export PATH="/usr/local/opt/curl/bin:$PATH" export PATH="/usr/local/opt/curl/bin:$PATH"
curl --version curl --version
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/macOS' -J '^SDWebImageWebPCoder$' -c -X gcov -F macos
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/iOS' -J '^SDWebImageWebPCoder$' -c -X gcov -F ios bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/iOS' -J '^SDWebImageWebPCoder$' -c -X gcov -F ios
bash <(curl -s https://codecov.io/bash) -v -D './DerivedData/tvOS' -J '^SDWebImageWebPCoder$' -c -X gcov -F tvos

View File

@ -1,2 +1,2 @@
github "SDWebImage/SDWebImage" ~> 5.15 github "SDWebImage/SDWebImage" ~> 5.16
github "SDWebImage/libwebp-Xcode" ~> 1.0 github "SDWebImage/libwebp-Xcode" ~> 1.0

View File

@ -37,7 +37,8 @@
NSURL *staticWebPURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/2.webp"]; NSURL *staticWebPURL = [NSURL URLWithString:@"https://www.gstatic.com/webp/gallery/2.webp"];
NSURL *animatedWebPURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/world-cup-2014-42.webp"]; NSURL *animatedWebPURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/world-cup-2014-42.webp"];
[self.imageView1 sd_setImageWithURL:staticWebPURL placeholderImage:nil options:0 context:@{SDWebImageContextImageThumbnailPixelSize : @(CGSizeMake(300, 300))} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { [self.imageView1 sd_setImageWithURL:staticWebPURL placeholderImage:nil options:0 context:@{SDWebImageContextImageScaleDownLimitBytes : @(1024 * 100)} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
NSCAssert(image.size.width < 200, @"Limit Bytes should limit image size to 186");
if (image) { if (image) {
NSLog(@"%@", @"Static WebP load success"); NSLog(@"%@", @"Static WebP load success");
} }

View File

@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
"state": { "state": {
"branch": null, "branch": null,
"revision": "966e6c3ee4569227ce67434d890bb22073ead2d6", "revision": "fb50c1d20f24db5322b2f8f379de3618f75fe08e",
"version": "5.5.0" "version": "5.15.5"
} }
} }
] ]

View File

@ -17,7 +17,7 @@ let package = Package(
dependencies: [ dependencies: [
// Dependencies declare other packages that this package depends on. // Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"), // .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.15.0"), .package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.16.0"),
.package(url: "https://github.com/SDWebImage/libwebp-Xcode.git", from: "1.1.0") .package(url: "https://github.com/SDWebImage/libwebp-Xcode.git", from: "1.1.0")
], ],
targets: [ targets: [

View File

@ -8,7 +8,6 @@ target 'SDWebImageWebPCoderExample' do
platform :ios, '9.0' platform :ios, '9.0'
project example_project_path project example_project_path
pod 'SDWebImageWebPCoder', :path => './' pod 'SDWebImageWebPCoder', :path => './'
pod 'SDWebImage', :path => '../SDWebImage'
end end
target 'SDWebImageWebPCoderTests' do target 'SDWebImageWebPCoderTests' do
@ -16,5 +15,4 @@ target 'SDWebImageWebPCoderTests' do
project test_project_path project test_project_path
pod 'Expecta' pod 'Expecta'
pod 'SDWebImageWebPCoder', :path => './' pod 'SDWebImageWebPCoder', :path => './'
pod 'SDWebImage', :path => '../SDWebImage'
end end

View File

@ -27,7 +27,7 @@ This is a SDWebImage coder plugin to support WebP image.
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1', 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) SD_WEBP=1 WEBP_USE_INTRINSICS=1',
'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src' 'USER_HEADER_SEARCH_PATHS' => '$(inherited) $(SRCROOT)/libwebp/src'
} }
s.dependency 'SDWebImage/Core', '~> 5.15' s.dependency 'SDWebImage/Core', '~> 5.16'
s.dependency 'libwebp', '~> 1.0' s.dependency 'libwebp', '~> 1.0'
end end

View File

@ -88,6 +88,20 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
return canvas; return canvas;
} }
// TODO, share this logic for multiple coders, or do refactory in v6.0 (The coder plugin should provide image information back to Core, like `CGImageSourceCopyPropertiesAtIndex`)
static inline CGSize SDCalculateScaleDownPixelSize(NSUInteger limitBytes, CGSize originalSize, NSUInteger frameCount, NSUInteger bytesPerPixel) {
if (CGSizeEqualToSize(originalSize, CGSizeZero)) return CGSizeMake(1, 1);
NSUInteger totalFramePixelSize = limitBytes / bytesPerPixel / (frameCount ?: 1);
CGFloat ratio = originalSize.height / originalSize.width;
CGFloat width = sqrt(totalFramePixelSize / ratio);
CGFloat height = width * ratio;
width = MAX(1, floor(width));
height = MAX(1, floor(height));
CGSize size = CGSizeMake(width, height);
return size;
}
@interface SDWebPCoderFrame : NSObject @interface SDWebPCoderFrame : NSObject
@property (nonatomic, assign) NSUInteger index; // Frame index (zero based) @property (nonatomic, assign) NSUInteger index; // Frame index (zero based)
@ -126,6 +140,7 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
NSUInteger _currentBlendIndex; NSUInteger _currentBlendIndex;
BOOL _preserveAspectRatio; BOOL _preserveAspectRatio;
CGSize _thumbnailSize; CGSize _thumbnailSize;
BOOL _limitBytes;
} }
- (void)dealloc { - (void)dealloc {
@ -218,6 +233,24 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
CGColorSpaceRef colorSpace = [self sd_createColorSpaceWithDemuxer:demuxer]; CGColorSpaceRef colorSpace = [self sd_createColorSpaceWithDemuxer:demuxer];
int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH); int canvasWidth = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH);
int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT); int canvasHeight = WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT);
uint32_t frameCount = WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT);
int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT);
NSUInteger limitBytes = 0;
NSNumber *limitBytesValue = options[SDImageCoderDecodeScaleDownLimitBytes];
if (limitBytesValue != nil) {
limitBytes = limitBytesValue.unsignedIntegerValue;
}
// Scale down to limit bytes if need
if (limitBytes > 0) {
// Hack 32 BitsPerPixel
CGSize imageSize = CGSizeMake(canvasWidth, canvasHeight);
CGSize framePixelSize = SDCalculateScaleDownPixelSize(limitBytes, imageSize, frameCount, 4);
// Override thumbnail size
thumbnailSize = framePixelSize;
preserveAspectRatio = YES;
}
// Check whether we need to use thumbnail // Check whether we need to use thumbnail
CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(canvasWidth, canvasHeight) scaleSize:thumbnailSize preserveAspectRatio:preserveAspectRatio shouldScaleUp:NO]; CGSize scaledSize = [SDImageCoderHelper scaledSizeWithImageSize:CGSizeMake(canvasWidth, canvasHeight) scaleSize:thumbnailSize preserveAspectRatio:preserveAspectRatio shouldScaleUp:NO];
@ -245,7 +278,6 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
return nil; return nil;
} }
int loopCount = WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT);
NSMutableArray<SDImageFrame *> *frames = [NSMutableArray array]; NSMutableArray<SDImageFrame *> *frames = [NSMutableArray array];
do { do {
@ -312,6 +344,12 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
preserveAspectRatio = preserveAspectRatioValue.boolValue; preserveAspectRatio = preserveAspectRatioValue.boolValue;
} }
_preserveAspectRatio = preserveAspectRatio; _preserveAspectRatio = preserveAspectRatio;
NSUInteger limitBytes = 0;
NSNumber *limitBytesValue = options[SDImageCoderDecodeScaleDownLimitBytes];
if (limitBytesValue != nil) {
limitBytes = limitBytesValue.unsignedIntegerValue;
}
_limitBytes = limitBytes;
_currentBlendIndex = NSNotFound; _currentBlendIndex = NSNotFound;
SD_LOCK_INIT(_lock); SD_LOCK_INIT(_lock);
} }
@ -352,6 +390,15 @@ static inline CGContextRef _Nullable CreateWebPCanvas(BOOL hasAlpha, CGSize canv
[self scanAndCheckFramesValidWithDemuxer:_demux]; [self scanAndCheckFramesValidWithDemuxer:_demux];
} }
SD_UNLOCK(_lock); SD_UNLOCK(_lock);
// Scale down to limit bytes if need
if (_limitBytes > 0) {
// Hack 32 BitsPerPixel
CGSize imageSize = CGSizeMake(_canvasWidth, _canvasHeight);
CGSize framePixelSize = SDCalculateScaleDownPixelSize(_limitBytes, imageSize, _frameCount, 4);
// Override thumbnail size
_thumbnailSize = framePixelSize;
_preserveAspectRatio = YES;
}
} }
- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
@ -911,6 +958,21 @@ static float GetFloatValueForKey(NSDictionary * _Nonnull dictionary, NSString *
preserveAspectRatio = preserveAspectRatioValue.boolValue; preserveAspectRatio = preserveAspectRatioValue.boolValue;
} }
_preserveAspectRatio = preserveAspectRatio; _preserveAspectRatio = preserveAspectRatio;
NSUInteger limitBytes = 0;
NSNumber *limitBytesValue = options[SDImageCoderDecodeScaleDownLimitBytes];
if (limitBytesValue != nil) {
limitBytes = limitBytesValue.unsignedIntegerValue;
}
_limitBytes = limitBytes;
// Scale down to limit bytes if need
if (_limitBytes > 0) {
// Hack 32 BitsPerPixel
CGSize imageSize = CGSizeMake(_canvasWidth, _canvasHeight);
CGSize framePixelSize = SDCalculateScaleDownPixelSize(_limitBytes, imageSize, _frameCount, 4);
// Override thumbnail size
_thumbnailSize = framePixelSize;
_preserveAspectRatio = YES;
}
_scale = scale; _scale = scale;
_demux = demuxer; _demux = demuxer;
_imageData = data; _imageData = data;

View File

@ -129,6 +129,9 @@ const int64_t kAsyncTestTimeout = 5;
XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"]; XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView view category"];
SDAnimatedImageView *imageView = [SDAnimatedImageView new]; SDAnimatedImageView *imageView = [SDAnimatedImageView new];
NSURL *testURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"]; NSURL *testURL = [NSURL URLWithString:@"http://littlesvr.ca/apng/images/SteamEngine.webp"];
NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:testURL];
[SDImageCache.sharedImageCache removeImageFromMemoryForKey:key];
[SDImageCache.sharedImageCache removeImageFromDiskForKey:key];
[imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveLoad progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { [imageView sd_setImageWithURL:testURL placeholderImage:nil options:SDWebImageProgressiveLoad progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = imageView.image; UIImage *image = imageView.image;

View File

@ -284,8 +284,8 @@
PRODUCT_NAME = SDWebImageWebPCoder; PRODUCT_NAME = SDWebImageWebPCoder;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = ""; VERSION_INFO_PREFIX = "";
@ -358,8 +358,8 @@
PRODUCT_NAME = SDWebImageWebPCoder; PRODUCT_NAME = SDWebImageWebPCoder;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvsimulator appletvos";
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0; TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic"; VERSIONING_SYSTEM = "apple-generic";