diff --git a/README.md b/README.md index de2a781..70ae978 100644 --- a/README.md +++ b/README.md @@ -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) +### 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 To run the example project, clone the repo, and run `pod install` from the root directory first. Then open `SDWebImageWebPCoder.xcworkspace`. diff --git a/SDWebImageWebPCoder.podspec b/SDWebImageWebPCoder.podspec index c5d68b4..2baea59 100644 --- a/SDWebImageWebPCoder.podspec +++ b/SDWebImageWebPCoder.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'SDWebImageWebPCoder' - s.version = '0.7.0' + s.version = '0.8.0' s.summary = 'WebP decoder/encoder for SDWebImage coder plugin.' s.description = <<-DESC diff --git a/SDWebImageWebPCoder.xcodeproj/project.pbxproj b/SDWebImageWebPCoder.xcodeproj/project.pbxproj index d4a8813..b375c0e 100644 --- a/SDWebImageWebPCoder.xcodeproj/project.pbxproj +++ b/SDWebImageWebPCoder.xcodeproj/project.pbxproj @@ -7,6 +7,14 @@ objects = { /* 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 */; }; 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, ); }; }; @@ -38,7 +46,8 @@ /* End PBXBuildFile 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 = ""; }; + 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDWebImageWebPCoderDefine.m; sourceTree = ""; }; + 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDWebImageWebPCoderDefine.h; sourceTree = ""; }; 3217BE7B220547EB003D0310 /* SDWebImageWebPCoder.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = SDWebImageWebPCoder.modulemap; sourceTree = ""; }; 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; }; @@ -59,7 +68,6 @@ 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 = ""; }; 80BFF2782136BEE000B95470 /* libwebp.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = libwebp.framework; path = Carthage/Build/watchOS/libwebp.framework; sourceTree = ""; }; - 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -102,22 +110,12 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 52FB3B532EE8775B69517E2E /* Pods */ = { - isa = PBXGroup; - children = ( - 28D8AA3D3015E075692FD3E3 /* Pods-SDWebImageWebPCoderTests.debug.xcconfig */, - D92E6791BF088D1A101E670E /* Pods-SDWebImageWebPCoderTests.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; 806E77932136A1C000A316D2 = { isa = PBXGroup; children = ( 806E77A82136A2E900A316D2 /* SDImageWebPCoder */, 806E779E2136A1C000A316D2 /* Products */, 80BFF2312136AA7D00B95470 /* Frameworks */, - 52FB3B532EE8775B69517E2E /* Pods */, ); sourceTree = ""; }; @@ -146,6 +144,8 @@ 806E77A92136A2E900A316D2 /* Classes */ = { isa = PBXGroup; children = ( + 220A6238257EAFB300262720 /* SDWebImageWebPCoderDefine.h */, + 220A6237257EAFB300262720 /* SDWebImageWebPCoderDefine.m */, 806E77AB2136A2E900A316D2 /* SDImageWebPCoder.h */, 806E77AE2136A2E900A316D2 /* SDImageWebPCoder.m */, 806E77AD2136A2E900A316D2 /* UIImage+WebP.h */, @@ -228,6 +228,7 @@ files = ( 806E77C72136A7AD00A316D2 /* SDWebImageWebPCoder.h in Headers */, 806E77B62136A2E900A316D2 /* UIImage+WebP.h in Headers */, + 220A623D257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */, 806E77B42136A2E900A316D2 /* SDImageWebPCoder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -238,6 +239,7 @@ files = ( 80BFF2502136BC1500B95470 /* UIImage+WebP.h in Headers */, 80BFF24D2136BC0600B95470 /* SDWebImageWebPCoder.h in Headers */, + 220A623E257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */, 80BFF24E2136BC1000B95470 /* SDImageWebPCoder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -248,6 +250,7 @@ files = ( 80BFF2632136BE2200B95470 /* SDWebImageWebPCoder.h in Headers */, 80BFF2612136BE1C00B95470 /* UIImage+WebP.h in Headers */, + 220A623F257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */, 80BFF25F2136BE1700B95470 /* SDImageWebPCoder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -258,6 +261,7 @@ files = ( 80BFF27F2136BEF200B95470 /* SDWebImageWebPCoder.h in Headers */, 80BFF27D2136BEED00B95470 /* UIImage+WebP.h in Headers */, + 220A6240257EAFB300262720 /* SDWebImageWebPCoderDefine.h in Headers */, 80BFF27B2136BEE700B95470 /* SDImageWebPCoder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -416,6 +420,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 228EA36125825A52005903D9 /* SDWebImageWebPCoderDefine.m in Sources */, 806E77B72136A2E900A316D2 /* SDImageWebPCoder.m in Sources */, 806E77B32136A2E900A316D2 /* UIImage+WebP.m in Sources */, ); @@ -425,6 +430,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 220A623A257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */, 80BFF24F2136BC1300B95470 /* SDImageWebPCoder.m in Sources */, 80BFF2512136BC1800B95470 /* UIImage+WebP.m in Sources */, ); @@ -434,6 +440,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 220A623B257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */, 80BFF2602136BE1A00B95470 /* SDImageWebPCoder.m in Sources */, 80BFF2622136BE1F00B95470 /* UIImage+WebP.m in Sources */, ); @@ -443,6 +450,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 220A623C257EAFB300262720 /* SDWebImageWebPCoderDefine.m in Sources */, 80BFF27C2136BEEB00B95470 /* SDImageWebPCoder.m in Sources */, 80BFF27E2136BEF000B95470 /* UIImage+WebP.m in Sources */, ); diff --git a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m index 9aaa45a..207aa1c 100644 --- a/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m +++ b/SDWebImageWebPCoder/Classes/SDImageWebPCoder.m @@ -7,6 +7,10 @@ */ #import "SDImageWebPCoder.h" +#import "SDWebImageWebPCoderDefine.h" +#import +#import +#import #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" @@ -22,7 +26,47 @@ @import libwebp; #endif -#import +#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 static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio, CGSize thumbnailSize) { @@ -98,7 +142,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio BOOL _finished; CGFloat _canvasWidth; CGFloat _canvasHeight; - dispatch_semaphore_t _lock; + SD_LOCK_DECLARE(_lock); NSUInteger _currentBlendIndex; BOOL _preserveAspectRatio; CGSize _thumbnailSize; @@ -291,7 +335,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio } _preserveAspectRatio = preserveAspectRatio; _currentBlendIndex = NSNotFound; - _lock = dispatch_semaphore_create(1); + SD_LOCK_INIT(_lock); } return self; } @@ -617,7 +661,11 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio BOOL encodeFirstFrame = [options[SDImageCoderEncodeFirstFrameOnly] boolValue]; if (encodeFirstFrame || frames.count == 0) { // 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 { // for animated webp image WebPMux *mux = WebPMuxNew(); @@ -626,7 +674,11 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio } for (size_t i = 0; i < frames.count; 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; WebPMuxFrameInfo frame = { .bitstream.bytes = webpData.bytes, .bitstream.size = webpData.length, @@ -663,7 +715,12 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio 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; if (!imageRef) { return nil; @@ -779,10 +836,7 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio return nil; } - 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.thread_level = 1; // Thread encoding for fast - config.lossless = 0; // Disable lossless encoding (If we need, can add new Encoding Options in future version) + [self updateWebPOptionsToConfig:&config maxFileSize:maxFileSize options:options]; picture.use_argb = 0; // Lossy encoding use YUV for internel bitstream picture.width = (int)width; picture.height = (int)height; @@ -830,6 +884,89 @@ static CGSize SDCalculateThumbnailSize(CGSize fullSize, BOOL preserveAspectRatio 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) { free((void *)data); } @@ -881,7 +1018,7 @@ static void FreeImageData(void *info, const void *data, size_t size) { _demux = demuxer; _imageData = data; _currentBlendIndex = NSNotFound; - _lock = dispatch_semaphore_create(1); + SD_LOCK_INIT(_lock); } return self; } diff --git a/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.h b/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.h new file mode 100644 index 0000000..dd972fe --- /dev/null +++ b/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.h @@ -0,0 +1,135 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#if __has_include() +#import +#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 diff --git a/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.m b/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.m new file mode 100644 index 0000000..ff333de --- /dev/null +++ b/SDWebImageWebPCoder/Classes/SDWebImageWebPCoderDefine.m @@ -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"; diff --git a/SDWebImageWebPCoder/Module/Info.plist b/SDWebImageWebPCoder/Module/Info.plist index 44f8cb0..bdaef62 100644 --- a/SDWebImageWebPCoder/Module/Info.plist +++ b/SDWebImageWebPCoder/Module/Info.plist @@ -15,9 +15,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.7.0 + 0.8.0 CFBundleVersion - 0.7.0 + 0.8.0 NSPrincipalClass diff --git a/SDWebImageWebPCoder/Module/SDWebImageWebPCoder.h b/SDWebImageWebPCoder/Module/SDWebImageWebPCoder.h index d0c0797..69e8947 100644 --- a/SDWebImageWebPCoder/Module/SDWebImageWebPCoder.h +++ b/SDWebImageWebPCoder/Module/SDWebImageWebPCoder.h @@ -12,4 +12,5 @@ FOUNDATION_EXPORT double SDWebImageWebPCoderVersionNumber; FOUNDATION_EXPORT const unsigned char SDWebImageWebPCoderVersionString[]; #import +#import #import diff --git a/Tests/SDWebImageWebPCoderTests.m b/Tests/SDWebImageWebPCoderTests.m index f2deee5..97ce68e 100644 --- a/Tests/SDWebImageWebPCoderTests.m +++ b/Tests/SDWebImageWebPCoderTests.m @@ -12,6 +12,19 @@ #import #import #import +#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() && __has_include() && __has_include() && __has_include() +#import +#import +#import +#import +#else +@import libwebp; +#endif 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 @end +@interface SDImageWebPCoder () +- (void) updateWebPOptionsToConfig:(WebPConfig * _Nonnull)config + maxFileSize:(NSUInteger)maxFileSize + options:(nullable SDImageCoderOptions *)options; +@end + @implementation SDWebImageWebPCoderTests + (void)setUp { @@ -196,6 +215,54 @@ const int64_t kAsyncTestTimeout = 5; 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 @implementation SDWebImageWebPCoderTests (Helpers)