Merge pull request #70 from SDWebImage/feat/encode_with_frames

Adopt 5.15.0's encodedDataWithFrames API
This commit is contained in:
DreamPiggy 2023-01-17 17:33:48 +08:00 committed by GitHub
commit 5864b77d88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 8 deletions

View File

@ -176,6 +176,9 @@ let image = SDImageWebPCoder.shared.decodedImage(with: data, options: [.decodeTh
// WebP image encoding // WebP image encoding
UIImage *image; UIImage *image;
NSData *webpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:nil]; NSData *webpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:nil];
// Animated encoding
NSArray<SDImageFrames *> *frames;
NSData *awebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithFrames:frames loopCount:0 format:SDImageFormatWebP options:nil];
// Encode Quality // Encode Quality
NSData *lossyWebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:@{SDImageCoderEncodeCompressionQuality : @(0.1)}]; // [0, 1] compression quality NSData *lossyWebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:@{SDImageCoderEncodeCompressionQuality : @(0.1)}]; // [0, 1] compression quality
NSData *limitedWebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:@{SDImageCoderEncodeMaxFileSize : @(1024 * 10)}]; // v0.6.0 feature, limit output file size <= 10KB NSData *limitedWebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:image format:SDImageFormatWebP options:@{SDImageCoderEncodeMaxFileSize : @(1024 * 10)}]; // v0.6.0 feature, limit output file size <= 10KB
@ -187,6 +190,9 @@ NSData *limitedWebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithImage:i
// WebP image encoding // WebP image encoding
let image: UIImage let image: UIImage
let webpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: nil) let webpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: nil)
// Animated encoding
let frames: [SDImageFrame]
let awebpData = SDImageWebPCoder.shared.encodedData(with: frames, loopCount: 0, format: .webP, options: nil)
// Encode Quality // Encode Quality
let lossyWebpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: [.encodeCompressionQuality: 0.1]) // [0, 1] compression quality let lossyWebpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: [.encodeCompressionQuality: 0.1]) // [0, 1] compression quality
let limitedWebpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: [.encodeMaxFileSize: 1024 * 10]) // v0.6.0 feature, limit output file size <= 10KB let limitedWebpData = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: [.encodeMaxFileSize: 1024 * 10]) // v0.6.0 feature, limit output file size <= 10KB
@ -212,6 +218,32 @@ let thumbnailWebpData = SDImageWebPCoder.shared.encodedData(with: image, format:
See more documentation in [SDWebImage Wiki - Coders](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-coder-420) See more documentation in [SDWebImage Wiki - Coders](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#custom-coder-420)
### Animated WebP Encoding (0.10+)
+ Objective-c
```objective-c
// Animated encoding
NSMutableArray<SDImageFrames *> *frames = [NSMutableArray array];
for (size_t i = 0; i < images.count; i++) {
SDImageFrame *frame = [SDImageFrame frameWithImage:images[i] duration:0.1];
[frames appendObject:frame];
}
NSData *awebpData = [[SDImageWebPCoder sharedCoder] encodedDataWithFrames:frames loopCount:0 format:SDImageFormatWebP options:nil];
```
+ Swift
```swift
// Animated encoding
var frames: [SDImageFrame] = []
for i in [0..<images.count] {
let frame = SDImageFrame(image: images[i], duration: 0.1)
frames.append(frame)
}
let awebpData = SDImageWebPCoder.shared.encodedData(with: frames, loopCount: 0, format: .webP, options: nil)
```
### Advanced WebP codec options (0.8+) ### Advanced WebP codec options (0.8+)
The WebP codec [libwebp](https://developers.google.com/speed/webp/docs/api) we use, supports some advanced control options for encoding/decoding. You can pass them to libwebp by using the wrapper top level API: The WebP codec [libwebp](https://developers.google.com/speed/webp/docs/api) we use, supports some advanced control options for encoding/decoding. You can pass them to libwebp by using the wrapper top level API:

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.13' s.dependency 'SDWebImage/Core', '~> 5.15'
s.dependency 'libwebp', '~> 1.0' s.dependency 'libwebp', '~> 1.0'
end end

View File

@ -595,6 +595,24 @@ else OSSpinLockUnlock(&lock##_deprecated);
if (!image) { if (!image) {
return nil; return nil;
} }
NSArray<SDImageFrame *> *frames = [SDImageCoderHelper framesFromAnimatedImage:image];
if (!frames || frames.count == 0) {
SDImageFrame *frame = [SDImageFrame frameWithImage:image duration:0];
frames = @[frame];
}
return [self encodedDataWithFrames:frames loopCount:image.sd_imageLoopCount format:format options:options];
}
- (NSData *)encodedDataWithFrames:(NSArray<SDImageFrame *> *)frames loopCount:(NSUInteger)loopCount format:(SDImageFormat)format options:(SDImageCoderOptions *)options {
UIImage *image = frames.firstObject.image; // Primary image
if (!image) {
return nil;
}
CGImageRef imageRef = image.CGImage;
if (!imageRef) {
// Earily return, supports CGImage only
return nil;
}
NSData *data; NSData *data;
@ -615,12 +633,11 @@ else OSSpinLockUnlock(&lock##_deprecated);
if (options[SDImageCoderEncodeMaxFileSize]) { if (options[SDImageCoderEncodeMaxFileSize]) {
maxFileSize = [options[SDImageCoderEncodeMaxFileSize] unsignedIntegerValue]; maxFileSize = [options[SDImageCoderEncodeMaxFileSize] unsignedIntegerValue];
} }
NSArray<SDImageFrame *> *frames = [SDImageCoderHelper framesFromAnimatedImage:image];
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
if (encodeFirstFrame || frames.count == 0) { if (encodeFirstFrame || frames.count <= 1) {
// for static single webp image // for static single webp image
data = [self sd_encodedWebpDataWithImage:image.CGImage data = [self sd_encodedWebpDataWithImage:imageRef
quality:compressionQuality quality:compressionQuality
maxPixelSize:maxPixelSize maxPixelSize:maxPixelSize
maxFileSize:maxFileSize maxFileSize:maxFileSize
@ -652,9 +669,8 @@ else OSSpinLockUnlock(&lock##_deprecated);
} }
} }
int loopCount = (int)image.sd_imageLoopCount;
WebPMuxAnimParams params = { .bgcolor = 0, WebPMuxAnimParams params = { .bgcolor = 0,
.loop_count = loopCount .loop_count = (int)loopCount
}; };
if (WebPMuxSetAnimationParams(mux, &params) != WEBP_MUX_OK) { if (WebPMuxSetAnimationParams(mux, &params) != WEBP_MUX_OK) {
WebPMuxDelete(mux); WebPMuxDelete(mux);

View File

@ -193,9 +193,9 @@ const int64_t kAsyncTestTimeout = 5;
NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"]; NSURL *staticWebPURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"TestImageStatic" withExtension:@"webp"];
NSData *data = [NSData dataWithContentsOfURL:staticWebPURL]; NSData *data = [NSData dataWithContentsOfURL:staticWebPURL];
SDImageWebPCoder *coder = [[SDImageWebPCoder alloc] initWithAnimatedImageData:data options:nil]; SDImageWebPCoder *coder = [[SDImageWebPCoder alloc] initWithAnimatedImageData:data options:nil];
XCTAssertTrue(coder.animatedImageFrameCount == 1); XCTAssertTrue(coder.animatedImageFrameCount == 0);
UIImage *image = [coder animatedImageFrameAtIndex:0]; UIImage *image = [coder animatedImageFrameAtIndex:0];
XCTAssertNotNil(image); XCTAssertNil(image);
Ivar ivar = class_getInstanceVariable(coder.class, "_canvas"); Ivar ivar = class_getInstanceVariable(coder.class, "_canvas");
CGContextRef canvas = ((CGContextRef (*)(id, Ivar))object_getIvar)(coder, ivar); CGContextRef canvas = ((CGContextRef (*)(id, Ivar))object_getIvar)(coder, ivar);
XCTAssert(canvas == NULL); XCTAssert(canvas == NULL);