Merge pull request #2 from SDWebImage/master

Updates from Main branch
This commit is contained in:
Antti Kortetmaa 2020-12-23 15:38:44 +02:00 committed by GitHub
commit 76edf76a3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 428 additions and 26 deletions

View File

@ -212,6 +212,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)
### 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:
+ Objective-C
```objective-c
UIImage *image;
SDImageCoderOptions *options = @{SDImageCoderEncodeWebPMethod: @(0), SDImageCoderEncodeWebPAlphaCompression: @(100)};
NSData *data = [SDImageWebPCoder.sharedCoder encodedDataWithImage:image format:SDImageFormatWebP options:options];
// Will translate into:
// config->method = 0;
// config->alpha_quality = 100;
```
+ Swift
```swift
let image: UIImage
let options = [.encodeWebPMethod: 0, .encodeWebPAlphaCompression: 100]
let data = SDImageWebPCoder.shared.encodedData(with: image, format: .webP, options: options)
// Will translate into:
// config->method = 0;
// config->alpha_quality = 100;
```
## Example ## Example
To run the example project, clone the repo, and run `pod install` from the root directory first. Then open `SDWebImageWebPCoder.xcworkspace`. To run the example project, clone the repo, and run `pod install` from the root directory first. Then open `SDWebImageWebPCoder.xcworkspace`.

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'SDWebImageWebPCoder' s.name = 'SDWebImageWebPCoder'
s.version = '0.7.0' s.version = '0.8.0'
s.summary = 'WebP decoder/encoder for SDWebImage coder plugin.' s.summary = 'WebP decoder/encoder for SDWebImage coder plugin.'
s.description = <<-DESC s.description = <<-DESC

View File

@ -7,6 +7,14 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
220A623A257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623B257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623C257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
220A623D257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A623E257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A623F257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
220A6240257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */ = {isa = PBXBuildFile; fileRef = 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */; settings = {ATTRIBUTES = (Public, ); }; };
228EA36125825A52005903D9 /* SDWebImageWebPCoderDefine.m in Sources */ = {isa = PBXBuildFile; fileRef = 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */; };
806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */; }; 806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */ = {isa = PBXBuildFile; fileRef = 806E77AA2136A2E900A316D2 /* UIImage+WebP.m */; };
806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */; settings = {ATTRIBUTES = (Public, ); }; };
806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; }; 806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */ = {isa = PBXBuildFile; fileRef = 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -38,7 +46,8 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.debug.xcconfig"; path = "Tests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.debug.xcconfig"; sourceTree = "<group>"; }; 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoderDefine.m; sourceTree = "<group>"; };
220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoderDefine.h; sourceTree = "<group>"; };
3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = "<group>"; }; 3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = "<group>"; };
46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 46F21AD7D1692EBAC4D0FF33 /* Pods_SDWebImageWebPCoderTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SDWebImageWebPCoderTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
806E779D2136A1C000A316D2 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 806E779D2136A1C000A316D2 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -59,7 +68,6 @@
80BFF26E2136BE7900B95470 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 80BFF26E2136BE7900B95470 /* SDWebImageWebPCoder.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageWebPCoder.framework; sourceTree = BUILT_PRODUCTS_DIR; };
80BFF2772136BEE000B95470 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/watchOS/SDWebImage.framework; sourceTree = "<group>"; }; 80BFF2772136BEE000B95470 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/watchOS/SDWebImage.framework; sourceTree = "<group>"; };
80BFF2782136BEE000B95470 /* libwebp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libwebp.framework; path = Carthage/Build/watchOS/libwebp.framework; sourceTree = "<group>"; }; 80BFF2782136BEE000B95470 /* libwebp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libwebp.framework; path = Carthage/Build/watchOS/libwebp.framework; sourceTree = "<group>"; };
D92E6791BF088D1A101E670E /* Pods-SDWebImageWebPCoderTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SDWebImageWebPCoderTests.release.xcconfig"; path = "Tests/Pods/Target Support Files/Pods-SDWebImageWebPCoderTests/Pods-SDWebImageWebPCoderTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -102,22 +110,12 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
52FB3B532EE8775B69517E2E /* Pods */ = {
isa = PBXGroup;
children = (
28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */,
D92E6791BF088D1A101E670E /* Pods-SDWebImageWebPCoderTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
806E77932136A1C000A316D2 = { 806E77932136A1C000A316D2 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
806E77A82136A2E900A316D2 /* SDImageWebPCoder */, 806E77A82136A2E900A316D2 /* SDImageWebPCoder */,
806E779E2136A1C000A316D2 /* Products */, 806E779E2136A1C000A316D2 /* Products */,
80BFF2312136AA7D00B95470 /* Frameworks */, 80BFF2312136AA7D00B95470 /* Frameworks */,
52FB3B532EE8775B69517E2E /* Pods */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -146,6 +144,8 @@
806E77A92136A2E900A316D2 /* Classes */ = { 806E77A92136A2E900A316D2 /* Classes */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */,
220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */,
806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */, 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */,
806E77AE2136A2E900A316D2 /* SDImageWebPCoder.m */, 806E77AE2136A2E900A316D2 /* SDImageWebPCoder.m */,
806E77AD2136A2E900A316D2 /* UIImage+WebP.h */, 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */,
@ -228,6 +228,7 @@
files = ( files = (
806E77C72136A7AD00A316D2 /* SDWebImageWebPCoder.h in Headers */, 806E77C72136A7AD00A316D2 /* SDWebImageWebPCoder.h in Headers */,
806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */, 806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */,
220A623D257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */, 806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -238,6 +239,7 @@
files = ( files = (
80BFF2502136BC1500B95470 /* UIImage+WebP.h in Headers */, 80BFF2502136BC1500B95470 /* UIImage+WebP.h in Headers */,
80BFF24D2136BC0600B95470 /* SDWebImageWebPCoder.h in Headers */, 80BFF24D2136BC0600B95470 /* SDWebImageWebPCoder.h in Headers */,
220A623E257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF24E2136BC1000B95470 /* SDImageWebPCoder.h in Headers */, 80BFF24E2136BC1000B95470 /* SDImageWebPCoder.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -248,6 +250,7 @@
files = ( files = (
80BFF2632136BE2200B95470 /* SDWebImageWebPCoder.h in Headers */, 80BFF2632136BE2200B95470 /* SDWebImageWebPCoder.h in Headers */,
80BFF2612136BE1C00B95470 /* UIImage+WebP.h in Headers */, 80BFF2612136BE1C00B95470 /* UIImage+WebP.h in Headers */,
220A623F257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF25F2136BE1700B95470 /* SDImageWebPCoder.h in Headers */, 80BFF25F2136BE1700B95470 /* SDImageWebPCoder.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -258,6 +261,7 @@
files = ( files = (
80BFF27F2136BEF200B95470 /* SDWebImageWebPCoder.h in Headers */, 80BFF27F2136BEF200B95470 /* SDWebImageWebPCoder.h in Headers */,
80BFF27D2136BEED00B95470 /* UIImage+WebP.h in Headers */, 80BFF27D2136BEED00B95470 /* UIImage+WebP.h in Headers */,
220A6240257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */,
80BFF27B2136BEE700B95470 /* SDImageWebPCoder.h in Headers */, 80BFF27B2136BEE700B95470 /* SDImageWebPCoder.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -416,6 +420,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
228EA36125825A52005903D9 /* SDWebImageWebPCoderDefine.m in Sources */,
806E77B72136A2E900A316D2 /* SDImageWebPCoder.m in Sources */, 806E77B72136A2E900A316D2 /* SDImageWebPCoder.m in Sources */,
806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */, 806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */,
); );
@ -425,6 +430,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
220A623A257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF24F2136BC1300B95470 /* SDImageWebPCoder.m in Sources */, 80BFF24F2136BC1300B95470 /* SDImageWebPCoder.m in Sources */,
80BFF2512136BC1800B95470 /* UIImage+WebP.m in Sources */, 80BFF2512136BC1800B95470 /* UIImage+WebP.m in Sources */,
); );
@ -434,6 +440,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
220A623B257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF2602136BE1A00B95470 /* SDImageWebPCoder.m in Sources */, 80BFF2602136BE1A00B95470 /* SDImageWebPCoder.m in Sources */,
80BFF2622136BE1F00B95470 /* UIImage+WebP.m in Sources */, 80BFF2622136BE1F00B95470 /* UIImage+WebP.m in Sources */,
); );
@ -443,6 +450,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
220A623C257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */,
80BFF27C2136BEEB00B95470 /* SDImageWebPCoder.m in Sources */, 80BFF27C2136BEEB00B95470 /* SDImageWebPCoder.m in Sources */,
80BFF27E2136BEF000B95470 /* UIImage+WebP.m in Sources */, 80BFF27E2136BEF000B95470 /* UIImage+WebP.m in Sources */,
); );

View File

@ -7,6 +7,10 @@
*/ */
#import "SDImageWebPCoder.h" #import "SDImageWebPCoder.h"
#import "SDWebImageWebPCoderDefine.h"
#import <Accelerate/Accelerate.h>
#import <os/lock.h>
#import <libkern/OSAtomic.h>
#if __has_include("webp/decode.h") && __has_include("webp/encode.h") && __has_include("webp/demux.h") && __has_include("webp/mux.h") #if __has_include("webp/decode.h") && __has_include("webp/encode.h") && __has_include("webp/demux.h") && __has_include("webp/mux.h")
#import "webp/decode.h" #import "webp/decode.h"
@ -22,7 +26,47 @@
@import libwebp; @import libwebp;
#endif #endif
#import <Accelerate/Accelerate.h> #define SD_USE_OS_UNFAIR_LOCK TARGET_OS_MACCATALYST ||\
(__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_10_0) ||\
(__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_12) ||\
(__TV_OS_VERSION_MIN_REQUIRED >= __TVOS_10_0) ||\
(__WATCH_OS_VERSION_MIN_REQUIRED >= __WATCHOS_3_0)
#ifndef SD_LOCK_DECLARE
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock
#else
#define SD_LOCK_DECLARE(lock) os_unfair_lock lock API_AVAILABLE(ios(10.0), tvos(10), watchos(3), macos(10.12)); \
OSSpinLock lock##_deprecated;
#endif
#endif
#ifndef SD_LOCK_INIT
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK_INIT(lock) lock = OS_UNFAIR_LOCK_INIT
#else
#define SD_LOCK_INIT(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) lock = OS_UNFAIR_LOCK_INIT; \
else lock##_deprecated = OS_SPINLOCK_INIT;
#endif
#endif
#ifndef SD_LOCK
#if SD_USE_OS_UNFAIR_LOCK
#define SD_LOCK(lock) os_unfair_lock_lock(&lock)
#else
#define SD_LOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_lock(&lock); \
else OSSpinLockLock(&lock##_deprecated);
#endif
#endif
#ifndef SD_UNLOCK
#if SD_USE_OS_UNFAIR_LOCK
#define SD_UNLOCK(lock) os_unfair_lock_unlock(&lock)
#else
#define SD_UNLOCK(lock) if (@available(iOS 10, tvOS 10, watchOS 3, macOS 10.12, *)) os_unfair_lock_unlock(&lock); \
else OSSpinLockUnlock(&lock##_deprecated);
#endif
#endif
/// Calculate the actual thumnail pixel size /// Calculate the actual thumnail pixel size
static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio, CGSize thumbnailSize) { static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio, CGSize thumbnailSize) {
@ -98,7 +142,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
BOOL _finished; BOOL _finished;
CGFloat _canvasWidth; CGFloat _canvasWidth;
CGFloat _canvasHeight; CGFloat _canvasHeight;
dispatch_semaphore_t _lock; SD_LOCK_DECLARE(_lock);
NSUInteger _currentBlendIndex; NSUInteger _currentBlendIndex;
BOOL _preserveAspectRatio; BOOL _preserveAspectRatio;
CGSize _thumbnailSize; CGSize _thumbnailSize;
@ -291,7 +335,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
} }
_preserveAspectRatio = preserveAspectRatio; _preserveAspectRatio = preserveAspectRatio;
_currentBlendIndex = NSNotFound; _currentBlendIndex = NSNotFound;
_lock = dispatch_semaphore_create(1); SD_LOCK_INIT(_lock);
} }
return self; return self;
} }
@ -617,7 +661,11 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue];
if (encodeFirstFrame || frames.count == 0) { if (encodeFirstFrame || frames.count == 0) {
// for static single webp image // for static single webp image
data = [self sd_encodedWebpDataWithImage:image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize]; data = [self sd_encodedWebpDataWithImage:image.CGImage
quality:compressionQuality
maxPixelSize:maxPixelSize
maxFileSize:maxFileSize
options:options];
} else { } else {
// for animated webp image // for animated webp image
WebPMux *mux = WebPMuxNew(); WebPMux *mux = WebPMuxNew();
@ -626,7 +674,11 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
} }
for (size_t i = 0; i < frames.count; i++) { for (size_t i = 0; i < frames.count; i++) {
SDImageFrame *currentFrame = frames[i]; SDImageFrame *currentFrame = frames[i];
NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage quality:compressionQuality maxPixelSize:maxPixelSize maxFileSize:maxFileSize]; NSData *webpData = [self sd_encodedWebpDataWithImage:currentFrame.image.CGImage
quality:compressionQuality
maxPixelSize:maxPixelSize
maxFileSize:maxFileSize
options:options];
int duration = currentFrame.duration * 1000; int duration = currentFrame.duration * 1000;
WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes,
.bitstream.size = webpData.length, .bitstream.size = webpData.length,
@ -663,7 +715,12 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
return data; return data;
} }
- (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef quality:(double)quality maxPixelSize:(CGSize)maxPixelSize maxFileSize:(NSUInteger)maxFileSize { - (nullable NSData *)sd_encodedWebpDataWithImage:(nullable CGImageRef)imageRef
quality:(double)quality
maxPixelSize:(CGSize)maxPixelSize
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options
{
NSData *webpData; NSData *webpData;
if (!imageRef) { if (!imageRef) {
return nil; return nil;
@ -779,10 +836,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
return nil; return nil;
} }
config.target_size = (int)maxFileSize; // Max filesize for output, 0 means use quality instead [self updateWebPOptionsToConfig:&config maxFileSize:maxFileSize options:options];
config.pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line
config.thread_level = 1; // Thread encoding for fast
config.lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version)
picture.use_argb = 0; // Lossy encoding use YUV for internel bitstream picture.use_argb = 0; // Lossy encoding use YUV for internel bitstream
picture.width = (int)width; picture.width = (int)width;
picture.height = (int)height; picture.height = (int)height;
@ -830,6 +884,89 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio
return webpData; return webpData;
} }
- (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options {
config->target_size = (int)maxFileSize; // Max filesize for output, 0 means use quality instead
config->pass = maxFileSize > 0 ? 6 : 1; // Use 6 passes for file size limited encoding, which is the default value of `cwebp` command line
config->lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version)
if ([options[SDImageCoderEncodeWebPMethod] intValue]) {
config->method = [options[SDImageCoderEncodeWebPMethod] intValue];
}
if ([options[SDImageCoderEncodeWebPPass] intValue]) {
config->pass = [options[SDImageCoderEncodeWebPPass] intValue];
}
if ([options[SDImageCoderEncodeWebPPreprocessing] intValue]) {
config->preprocessing = [options[SDImageCoderEncodeWebPPreprocessing] intValue];
}
if ([options[SDImageCoderEncodeWebPThreadLevel] intValue]) {
config->thread_level = [options[SDImageCoderEncodeWebPThreadLevel] intValue];
} else {
config->thread_level = 1;
}
if ([options[SDImageCoderEncodeWebPLowMemory] intValue]) {
config->low_memory = [options[SDImageCoderEncodeWebPLowMemory] intValue];
}
if ([options[SDImageCoderEncodeWebPTargetPSNR] floatValue]) {
config->target_PSNR = [options[SDImageCoderEncodeWebPTargetPSNR] floatValue];
}
if ([options[SDImageCoderEncodeWebPSegments] intValue]) {
config->segments = [options[SDImageCoderEncodeWebPSegments] intValue];
}
if ([options[SDImageCoderEncodeWebPSnsStrength] intValue]) {
config->sns_strength = [options[SDImageCoderEncodeWebPSnsStrength] intValue];
}
if ([options[SDImageCoderEncodeWebPFilterStrength] intValue]) {
config->filter_strength = [options[SDImageCoderEncodeWebPFilterStrength] intValue];
}
if ([options[SDImageCoderEncodeWebPFilterSharpness] intValue]) {
config->filter_sharpness = [options[SDImageCoderEncodeWebPFilterSharpness] intValue];
}
if ([options[SDImageCoderEncodeWebPFilterType] intValue]) {
config->filter_type = [options[SDImageCoderEncodeWebPFilterType] intValue];
}
if ([options[SDImageCoderEncodeWebPAutofilter] intValue]) {
config->autofilter = [options[SDImageCoderEncodeWebPAutofilter] intValue];
}
if ([options[SDImageCoderEncodeWebPAlphaCompression] intValue]) {
config->alpha_compression = [options[SDImageCoderEncodeWebPAlphaCompression] intValue];
}
if ([options[SDImageCoderEncodeWebPAlphaFiltering] intValue]) {
config->alpha_filtering = [options[SDImageCoderEncodeWebPAlphaFiltering] intValue];
}
if ([options[SDImageCoderEncodeWebPAlphaQuality] intValue]) {
config->alpha_quality = [options[SDImageCoderEncodeWebPAlphaQuality] intValue];
}
if ([options[SDImageCoderEncodeWebPShowCompressed] intValue]) {
config->show_compressed = [options[SDImageCoderEncodeWebPShowCompressed] intValue];
}
if ([options[SDImageCoderEncodeWebPPartitions] intValue]) {
config->partitions = [options[SDImageCoderEncodeWebPPartitions] intValue];
}
if ([options[SDImageCoderEncodeWebPPartitionLimit] intValue]) {
config->partition_limit = [options[SDImageCoderEncodeWebPPartitionLimit] intValue];
}
if ([options[SDImageCoderEncodeWebPUseSharpYuv] intValue]) {
config->use_sharp_yuv = [options[SDImageCoderEncodeWebPUseSharpYuv] intValue];
}
}
static void FreeImageData(void *info, const void *data, size_t size) { static void FreeImageData(void *info, const void *data, size_t size) {
free((void *)data); free((void *)data);
} }
@ -881,7 +1018,7 @@ static void FreeImageData(void *info, const void *data, size_t size) {
_demux = demuxer; _demux = demuxer;
_imageData = data; _imageData = data;
_currentBlendIndex = NSNotFound; _currentBlendIndex = NSNotFound;
_lock = dispatch_semaphore_create(1); SD_LOCK_INIT(_lock);
} }
return self; return self;
} }

View File

@ -0,0 +1,135 @@
/*
* This file is part of the SDWebImage package.
* (c) Olivier Poitrey <rs@dailymotion.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#if __has_include(<SDWebImage/SDWebImage.h>)
#import <SDWebImage/SDWebImage.h>
#else
@import SDWebImage;
#endif
NS_ASSUME_NONNULL_BEGIN
/**
Integer value
Quality/speed trade-off (0=fast, 6=slower-better)
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPMethod;
/**
Integer value
Number of entropy-analysis passes (in [1..10])
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPass;
/**
Integer value
Preprocessing filter (0=none, 1=segment-smooth)
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPreprocessing;
/**
Float value
if non-zero, specifies the minimal distortion to try to achieve. Takes precedence over target_size.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPTargetPSNR;
/**
Integer value
If non-zero, try and use multi-threaded encoding.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPThreadLevel;
/**
Integer value
If set, reduce memory usage (but increase CPU use).
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPLowMemory;
/**
Integer value
if non-zero, specifies the minimal distortion to try to achieve. Takes precedence over target_size.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPSegments;
/**
Integer value
Spatial Noise Shaping. 0=off, 100=maximum.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPSnsStrength;
/**
Integer value
Range: [0 = off .. 100 = strongest]
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterStrength;
/**
Integer value
range: [0 = off .. 7 = least sharp]
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterSharpness;
/**
Integer value
Filtering type: 0 = simple, 1 = strong (only used If filter_strength > 0 or autofilter > 0)
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterType;
/**
Integer value
Auto adjust filter's strength [0 = off, 1 = on]
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAutofilter;
/**
Integer value
Algorithm for encoding the alpha plane (0 = none, 1 = compressed with WebP lossless). Default is 1.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaCompression;
/**
Integer value
Predictive filtering method for alpha plane. 0: none, 1: fast, 2: best. Default if 1.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaFiltering;
/**
Integer value
Between 0 (smallest size) and 100 (lossless).
Default is 100.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaQuality;
/**
Integer value
If true, export the compressed picture back.
In-loop filtering is not applied.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPShowCompressed;
/**
Integer
Log2(number of token partitions) in [0..3]
Default is set to 0 for easier progressive decoding.
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPartitions;
/**
Integer value
Quality degradation allowed to fit the 512k limit on
Prediction modes coding (0: no degradation, 100: maximum possible degradation).
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPartitionLimit;
/**
Integer value
if needed, use sharp (and slow) RGB->YUV conversion
*/
FOUNDATION_EXPORT SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPUseSharpYuv;
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,28 @@
//
// SDWebImageWebPCoderDefine.m
// SDWebImageWebPCoder
//
// Created by Antti Kortetmaa on 2020/12/06.
//
#import "SDWebImageWebPCoderDefine.h"
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPMethod = @"webPMethod";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPass = @"webPPass";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPreprocessing = @"webPPreprocessing";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPThreadLevel = @"webPThreadLevel";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPLowMemory = @"webPLowMemory";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPTargetPSNR = @"webPTargetPSNR";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPSegments = @"webPSegments";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPSnsStrength = @"webPSnsStrength";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterStrength = @"webPFilterStrength";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterSharpness = @"webPFilterSharpness";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPFilterType = @"webPFilterType";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAutofilter = @"webPAutofilter";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaCompression = @"webPAlphaCompression";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaFiltering = @"webPAlphaFiltering";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPAlphaQuality = @"webPAlphaQuality";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPShowCompressed = @"webPShowCompressed";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPartitions = @"webPPartitions";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPPartitionLimit = @"webPPartitionLimit";
SDImageCoderOption _Nonnull const SDImageCoderEncodeWebPUseSharpYuv = @"webPUseSharpYuv";

View File

@ -15,9 +15,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.7.0</string> <string>0.8.0</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>0.7.0</string> <string>0.8.0</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string></string> <string></string>
</dict> </dict>

View File

@ -12,4 +12,5 @@ FOUNDATION_EXPORT double SDWebImageWebPCoderVersionNumber;
FOUNDATION_EXPORT const unsigned char SDWebImageWebPCoderVersionString[]; FOUNDATION_EXPORT const unsigned char SDWebImageWebPCoderVersionString[];
#import <SDWebImageWebPCoder/SDImageWebPCoder.h> #import <SDWebImageWebPCoder/SDImageWebPCoder.h>
#import <SDWebImageWebPCoder/SDWebImageWebPCoderDefine.h>
#import <SDWebImageWebPCoder/UIImage+WebP.h> #import <SDWebImageWebPCoder/UIImage+WebP.h>

View File

@ -12,6 +12,19 @@
#import <SDWebImageWebPCoder/SDWebImageWebPCoder.h> #import <SDWebImageWebPCoder/SDWebImageWebPCoder.h>
#import <Expecta/Expecta.h> #import <Expecta/Expecta.h>
#import <objc/runtime.h> #import <objc/runtime.h>
#if __has_include("webp/decode.h") && __has_include("webp/encode.h") && __has_include("webp/demux.h") && __has_include("webp/mux.h")
#import "webp/decode.h"
#import "webp/encode.h"
#import "webp/demux.h"
#import "webp/mux.h"
#elif __has_include(<libwebp/decode.h>) && __has_include(<libwebp/encode.h>) && __has_include(<libwebp/demux.h>) && __has_include(<libwebp/mux.h>)
#import <libwebp/decode.h>
#import <libwebp/encode.h>
#import <libwebp/demux.h>
#import <libwebp/mux.h>
#else
@import libwebp;
#endif
const int64_t kAsyncTestTimeout = 5; const int64_t kAsyncTestTimeout = 5;
@ -30,6 +43,12 @@ const int64_t kAsyncTestTimeout = 5;
@property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND @property (nonatomic, assign) NSUInteger blendFromIndex; // The nearest previous frame index which blend mode is WEBP_MUX_BLEND
@end @end
@interface SDImageWebPCoder ()
- (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config
maxFileSize:(NSUInteger)maxFileSize
options:(nullable SDImageCoderOptions *)options;
@end
@implementation SDWebImageWebPCoderTests @implementation SDWebImageWebPCoderTests
+ (void)setUp { + (void)setUp {
@ -196,6 +215,54 @@ const int64_t kAsyncTestTimeout = 5;
XCTAssertLessThanOrEqual(dataWithLimit.length, maxFileSize); XCTAssertLessThanOrEqual(dataWithLimit.length, maxFileSize);
} }
- (void)testEncodingSettings {
WebPConfig config;
WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 0.2);
SDImageCoderOptions *options = @{ SDImageCoderEncodeWebPMethod: @1,
SDImageCoderEncodeWebPPass: @2,
SDImageCoderEncodeWebPPreprocessing: @3,
SDImageCoderEncodeWebPThreadLevel: @4,
SDImageCoderEncodeWebPLowMemory: @5,
SDImageCoderEncodeWebPTargetPSNR: @6,
SDImageCoderEncodeWebPSegments: @7,
SDImageCoderEncodeWebPSnsStrength: @8,
SDImageCoderEncodeWebPFilterStrength: @9,
SDImageCoderEncodeWebPFilterSharpness: @10,
SDImageCoderEncodeWebPFilterType: @11,
SDImageCoderEncodeWebPAutofilter: @12,
SDImageCoderEncodeWebPAlphaCompression: @13,
SDImageCoderEncodeWebPAlphaFiltering: @14,
SDImageCoderEncodeWebPAlphaQuality: @15,
SDImageCoderEncodeWebPShowCompressed: @16,
SDImageCoderEncodeWebPPartitions: @17,
SDImageCoderEncodeWebPPartitionLimit: @18,
SDImageCoderEncodeWebPUseSharpYuv: @19 };
[SDImageWebPCoder.sharedCoder updateWebPOptionsToConfig:&config maxFileSize:1200 options:options];
expect(config.method).to.equal(1);
expect(config.pass).to.equal(2);
expect(config.preprocessing).to.equal(3);
expect(config.thread_level).to.equal(4);
expect(config.low_memory).to.equal(5);
expect(config.target_PSNR).to.equal(6);
expect(config.segments).to.equal(7);
expect(config.sns_strength).to.equal(8);
expect(config.filter_strength).to.equal(9);
expect(config.filter_sharpness).to.equal(10);
expect(config.filter_type).to.equal(11);
expect(config.autofilter).to.equal(12);
expect(config.alpha_compression).to.equal(13);
expect(config.alpha_filtering).to.equal(14);
expect(config.alpha_quality).to.equal(15);
expect(config.show_compressed).to.equal(16);
expect(config.partitions).to.equal(17);
expect(config.partition_limit).to.equal(18);
expect(config.use_sharp_yuv).to.equal(19);
}
@end @end
@implementation SDWebImageWebPCoderTests (Helpers) @implementation SDWebImageWebPCoderTests (Helpers)